<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: V</title>
    <description>The latest articles on DEV Community by V (@veevidify).</description>
    <link>https://dev.to/veevidify</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F140073%2Fcc59d437-e175-419d-93d5-32d52b8bff80.jpg</url>
      <title>DEV Community: V</title>
      <link>https://dev.to/veevidify</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/veevidify"/>
    <language>en</language>
    <item>
      <title>1-liner Docker commands for React project</title>
      <dc:creator>V</dc:creator>
      <pubDate>Wed, 10 Mar 2021 09:53:34 +0000</pubDate>
      <link>https://dev.to/veevidify/1-liner-docker-commands-for-react-project-4i31</link>
      <guid>https://dev.to/veevidify/1-liner-docker-commands-for-react-project-4i31</guid>
      <description>

&lt;h1&gt;
  
  
  Contents
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Contents&lt;/li&gt;
&lt;li&gt;Intro&lt;/li&gt;
&lt;li&gt;Obtain &lt;code&gt;node_modules&lt;/code&gt; Dependencies&lt;/li&gt;
&lt;li&gt;
Start Development Scripts

&lt;ul&gt;
&lt;li&gt;Developments Server&lt;/li&gt;
&lt;li&gt;Running &lt;code&gt;jest&lt;/code&gt; with &lt;code&gt;--watchAll&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Optional Improvements

&lt;ul&gt;
&lt;li&gt;Shell Script Wrapper&lt;/li&gt;
&lt;li&gt;Pre-commit Hooks with &lt;code&gt;husky&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Repo&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Final Thoughts&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;Let's say you're primarily a backend developer who works with &lt;code&gt;docker&lt;/code&gt; frequently, and you don't want to have &lt;code&gt;nvm&lt;/code&gt; and multiple &lt;code&gt;node&lt;/code&gt; versions installed. You still want to checkout a frontend project, and maybe start a &lt;code&gt;node&lt;/code&gt;/&lt;code&gt;react&lt;/code&gt; frontend to see how your system connects, or maybe perform some static analysis on your IDE, these are some good one-liner &lt;code&gt;docker&lt;/code&gt; commands to quickly get it up and running. No &lt;code&gt;node&lt;/code&gt;/&lt;code&gt;npm&lt;/code&gt; needed in your host, no custom &lt;code&gt;Dockerfile&lt;/code&gt; or &lt;code&gt;docker build&lt;/code&gt; process required.&lt;/p&gt;




&lt;h1&gt;
  
  
  Obtain &lt;code&gt;node_modules&lt;/code&gt; Dependencies
&lt;/h1&gt;

&lt;p&gt;After pulling your project from source control, &lt;code&gt;cd /your/project/folder&lt;/code&gt;, run the following &lt;code&gt;docker&lt;/code&gt; command in a terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;:/app"&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"/app"&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nv"&gt;$UID&lt;/span&gt; node:12-alpine yarn &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: I'm using &lt;code&gt;yarn&lt;/code&gt; here, if you're using &lt;code&gt;npm&lt;/code&gt;, simply replace &lt;code&gt;yarn install&lt;/code&gt; with &lt;code&gt;npm i&lt;/code&gt; (shorthand) or &lt;code&gt;npm install&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;outputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn &lt;span class="nb"&gt;install &lt;/span&gt;v1.22.5
&lt;span class="o"&gt;[&lt;/span&gt;1/4] Resolving packages...
&lt;span class="o"&gt;[&lt;/span&gt;2/4] Fetching packages...
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can notice &lt;code&gt;node_modules&lt;/code&gt; being populated in your host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;node_modules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;outputs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;drwxr-xr-x 1050 user user  36864 Mar  9 20:27 node_modules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The idea is to run a container while volume-mounting our host folder to the container. As we obtain &lt;code&gt;node_modules&lt;/code&gt; using &lt;code&gt;yarn install&lt;/code&gt; from within the container, with volume mounting, we effectively persist it into our host workspace folder, which allows us to perform static analysis afterwards.&lt;/p&gt;

&lt;p&gt;Let's break down this command so next time you can remember it instead of having to pull out your notes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;node:12-alpine&lt;/code&gt;: Name of the &lt;code&gt;Dockerfile&lt;/code&gt; which we will pull from Docker hub in order to run our container. You can check out other tags for &lt;code&gt;node&lt;/code&gt; images on: &lt;a href="https://hub.docker.com/_/node/"&gt;https://hub.docker.com/_/node/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--rm&lt;/code&gt; and &lt;code&gt;-it&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--rm&lt;/code&gt; tells docker to clean up the trailing container after &lt;code&gt;yarn install&lt;/code&gt; completes and the script succeeds.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-it&lt;/code&gt; indicates interactive mode, which connects &lt;code&gt;stdin/stdout&lt;/code&gt; of the container, redirecting input/output from/to your terminal shell.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-v&lt;/code&gt;, &lt;code&gt;-w&lt;/code&gt; and &lt;code&gt;-u&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-v "$(pwd):/app"&lt;/code&gt;: We're mounting the project's folder into &lt;code&gt;/app&lt;/code&gt; inside the container. A common way to build &lt;code&gt;Dockerfile&lt;/code&gt; for a &lt;code&gt;node&lt;/code&gt; app (for example for CI/CD or containerised deployments) is to use &lt;code&gt;ADD&lt;/code&gt; or &lt;code&gt;COPY&lt;/code&gt; directive in your &lt;code&gt;Dockerfile&lt;/code&gt;. However we're directly mounting the host files to avoid rebuilding the container at every change, for ease of development.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-w "/app&lt;/code&gt;": This parameter sets the container &lt;code&gt;WORKDIR&lt;/code&gt; to &lt;code&gt;/app&lt;/code&gt;, the same directory we mounted our code into, in order to make every command (e.g. &lt;code&gt;yarn install&lt;/code&gt; or &lt;code&gt;yarn start&lt;/code&gt;) we &lt;code&gt;docker run&lt;/code&gt; to point at the folder.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-u $UID&lt;/code&gt;: With volume mounting, commands we execute inside the container's mounted volume will generate files that are then persisted back on the host's project folder. With &lt;code&gt;-u&lt;/code&gt; set, we execute the command as the host's user &lt;code&gt;uid&lt;/code&gt;, so we have full control over our host's &lt;code&gt;node_modules&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Start Development Scripts
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Developments Server
&lt;/h3&gt;

&lt;p&gt;To start development server and test your app, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;:/app"&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"/app"&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nv"&gt;$UID&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CHOKIDAR_USEPOLLING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="nt"&gt;--env-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/.env"&lt;/span&gt; node:12-alpine yarn start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;outputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compiled successfully!

You can now view react-docker in the browser.

  Local:            http://localhost:3000
  On Your Network:  http://172.17.0.2:3000

Note that the development build is not optimized.
To create a production build, use yarn build.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our app is up and running:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v8Xk1oMx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0mea5344lxxwtjt2zh3r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v8Xk1oMx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0mea5344lxxwtjt2zh3r.png" alt="App" width="880" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apart from the config parameters applied similarly to our &lt;code&gt;yarn install&lt;/code&gt; script, we add a few more for development purposes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-p 3000:3000&lt;/code&gt;: I'm testing with a &lt;code&gt;react&lt;/code&gt; project. Since the default &lt;code&gt;react-scripts start&lt;/code&gt; runs on port 3000, I want to map that port to my host's port, which could be arbitrary instead of &lt;code&gt;3000&lt;/code&gt; (say for example you're running multiple front-end projects). This makes the development server accessible via &lt;code&gt;localhost:3000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-e CHOKIDAR_USEPOLLING=true&lt;/code&gt;: With this option, &lt;code&gt;node&lt;/code&gt; from within the container will be able to watch any change in the project's mounted files, and reload the app accordingly with the configured webpack inside &lt;code&gt;react-scripts&lt;/code&gt;. Take out this option if you don't want live polling for file changes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--env-file="$(pwd)/.env&lt;/code&gt;: &lt;code&gt;react&lt;/code&gt; as well as many other front-end libraries want to make use of environment variables, for example for different build target, different feature flags, etc. This option will forward all the variables declared in your project's folder's &lt;code&gt;.env&lt;/code&gt; file to the container environment variables, which can be convenient for testing. Take this option out if you don't use environment variables in your setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice how &lt;code&gt;react-scripts&lt;/code&gt; is letting us know the development server is accessible via &lt;a href="http://172.17.0.2:3000/"&gt;http://172.17.0.2:3000/&lt;/a&gt;. This is simply the container service provided ip address by docker default network. We don't have to concern ourselves with this because we'll never access it from within the container. And since the host port is mapped to the container's port, we can access it on our host computer browser via localhost:3000.&lt;/p&gt;
&lt;h3&gt;
  
  
  Running &lt;code&gt;jest&lt;/code&gt; with &lt;code&gt;--watchAll&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;If you use &lt;code&gt;react-scripts&lt;/code&gt; or &lt;code&gt;jest&lt;/code&gt;, with the following configs in &lt;code&gt;package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts start"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts start"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest --coverage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you would like to run test watch, simply use these configs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;:/app"&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"/app"&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nv"&gt;$UID&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CHOKIDAR_USEPOLLING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="nt"&gt;--env-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/.env"&lt;/span&gt; node:12-alpine yarn &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--watchAll&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;outputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn run v1.22.5
$ react-scripts test --watchAll
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; PASS  src/App.test.tsx
  ✓ renders learn react link (37 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.349 s
Ran all test suites.

Watch Usage
 › Press f to run only failed tests.
 › Press o to only run tests related to changed files.
 › Press q to quit watch mode.
 › Press p to filter by a filename regex pattern.
 › Press t to filter by a test name regex pattern.
 › Press Enter to trigger a test run.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;code&gt;--watch&lt;/code&gt;, while giving better performance isn't possible without &lt;code&gt;git&lt;/code&gt; installed, which is the case for the pre-built node alpine image on dockerhub. For a more feature-rich containerised set-up, refer to this great article by Michael Herman: Dockerizing a React App.&lt;/em&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Optional Improvements
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Shell Script Wrapper
&lt;/h3&gt;

&lt;p&gt;You can notice how the parameters can be set similarly for each of our &lt;code&gt;yarn&lt;/code&gt;/&lt;code&gt;npm&lt;/code&gt; command. Thus, it would be reasonable to wrap them in a &lt;code&gt;bash&lt;/code&gt; script, accept arbitrary arguments, so we can call the containerised &lt;code&gt;yarn&lt;/code&gt; with any subcommand or parameters.&lt;/p&gt;

&lt;p&gt;If you use the one-liner command, write this script, name it something like &lt;code&gt;docker-yarn.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"yarn &lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;:/app"&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"/app"&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nv"&gt;$UID&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CHOKIDAR_USEPOLLING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="nt"&gt;--env-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/.env"&lt;/span&gt; node:12-alpine yarn &lt;span class="nv"&gt;$args&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;em&gt;Note&lt;/em&gt;: Substitute &lt;code&gt;yarn&lt;/code&gt; for &lt;code&gt;npm&lt;/code&gt; if you use &lt;code&gt;npm&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;em&gt;Note&lt;/em&gt;: I'm using &lt;code&gt;-i&lt;/code&gt; instead of &lt;code&gt;-it&lt;/code&gt; for &lt;code&gt;husky&lt;/code&gt;'s &lt;code&gt;git&lt;/code&gt; hooks explained below.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;chmod&lt;/code&gt; and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;ug+x docker-yarn.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
./docker-yarn.sh &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Git Hooks with &lt;code&gt;husky&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;If you have a pre-commit hook like &lt;code&gt;husky&lt;/code&gt; installed, this will be what your project likely has in &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"husky"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^5.1.3"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and say &lt;code&gt;.husky/pre-push&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/_/husky.sh"&lt;/span&gt;

yarn run lint &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--watchAll&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since you don't want to change your &lt;code&gt;devDependencies&lt;/code&gt; (other team members might depend on it), and you want your &lt;code&gt;npm&lt;/code&gt; to be dockerised, you can create a shell script similar to the above section (Bash script wrapper) which wraps a dockerised &lt;code&gt;yarn&lt;/code&gt;/&lt;code&gt;npm&lt;/code&gt;, then alias/symlink it as &lt;code&gt;npm&lt;/code&gt; for your host machine.&lt;/p&gt;

&lt;p&gt;For demonstration, I'll put it inside &lt;code&gt;/var/scripts/docker-yarn.sh&lt;/code&gt;. Then pick a directory that is included in your &lt;code&gt;PATH&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;outputs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...:/usr/local/sbin:/usr/local/bin:...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One of mine includes &lt;code&gt;/usr/local/bin&lt;/code&gt;, so I'll be symlink the &lt;code&gt;yarn&lt;/code&gt; wrapper there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /var/scripts/docker-yarn.sh /usr/local/bin/yarn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To confirm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
which yarn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;outputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/local/bin/yarn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;which yarn&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;outputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

args="$@"
echo "yarn $args"
docker run --rm -i -v "$(pwd):/app" -w "/app" -u $UID -e CHOKIDAR_USEPOLLING=true --env-file="$(pwd)/.env" node:12-alpine yarn $args
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make sure it is working, run a &lt;code&gt;yarn&lt;/code&gt; command with arguments. Here I'm testing by installing a package, and running &lt;code&gt;yarn test --watch&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Installing package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
yarn add date-fns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;outputs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add date-fns
yarn add v1.22.5
[1/4] Resolving packages...
[2/4] Fetching packages...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Double check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; node_modules | &lt;span class="nb"&gt;grep &lt;/span&gt;date-fns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;outputs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;drwxr-xr-x  209 user user  12288 Mar  9 22:02 date-fns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
yarn &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--watch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;outputs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn test --watch
yarn run v1.22.5
$ react-scripts test --watch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PASS  src/App.test.tsx
  ✓ renders learn react link (52 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.283 s
Ran all test suites.

Watch Usage
 › Press f to run only failed tests.
 › Press o to only run tests related to changed files.
 › Press q to quit watch mode.
 › Press p to filter by a filename regex pattern.
 › Press t to filter by a test name regex pattern.
 › Press Enter to trigger a test run.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally our &lt;code&gt;git&lt;/code&gt; hooks. Commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"fix: wrapper script"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;outputs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn run lint
yarn run v1.22.5
$ eslint --fix
Done in 0.41s.
[master f8e398c] fix: wrapper script
 Date: Wed Mar 10 20:37:36 2021 +1100
 1 file changed, 3 insertions(+), 4 deletions(-)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;push:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;
git push origin master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;outputs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn run lint
yarn run v1.22.5
$ eslint --fix
Done in 0.41s.
yarn test --watchAll=false
yarn run v1.22.5
$ react-scripts test --watchAll=false
PASS src/App.test.tsx
  ✓ renders learn react link (46 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.769 s
Ran all test suites.
Done in 4.06s.
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 413 bytes | 413.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To github.com:veevidify/react-docker.git
   ec7162b..f8e398c  master -&amp;gt; master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Repo
&lt;/h3&gt;

&lt;p&gt;Repository for reference: &lt;a href="https://github.com/veevidify/react-docker"&gt;https://github.com/veevidify/react-docker&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Final Thoughts
&lt;/h1&gt;

&lt;p&gt;If you work primarily with front-end projects like &lt;code&gt;react&lt;/code&gt;, I would recommend using &lt;code&gt;nvm&lt;/code&gt; instead of containerised, since any issue would be much easier to troubleshoot. However, this article aimed to show you how powerful &lt;code&gt;docker&lt;/code&gt; can be, and with some basic understanding of image, container and volume, with a couple of clever configs, we can achieve almost any environment or setup.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>beginners</category>
      <category>react</category>
    </item>
    <item>
      <title>docker-compose up your entire Laravel + Apache + MySQL development environment.</title>
      <dc:creator>V</dc:creator>
      <pubDate>Thu, 04 Apr 2019 14:28:30 +0000</pubDate>
      <link>https://dev.to/veevidify/docker-compose-up-your-entire-laravel-apache-mysql-development-environment-45ea</link>
      <guid>https://dev.to/veevidify/docker-compose-up-your-entire-laravel-apache-mysql-development-environment-45ea</guid>
      <description>&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Contents&lt;/li&gt;
&lt;li&gt;Intro&lt;/li&gt;
&lt;li&gt;The set-up&lt;/li&gt;
&lt;li&gt;Webserver image for Laravel&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Up and Running&lt;/li&gt;
&lt;li&gt;
Helper scripts (optional)

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;container&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;db&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;composer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;php-artisan&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;phpunit&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;TL;DR&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;When on-boarding new devs to contribute to your project, you probably don't want them to spend hours hopping between documentations and StackOverflow, figuring out how to get anything working. There is just so much stuffs they would potentially have to go through to have a version of the app running locally: php, ini config, php extensions, apache configs, apache site-enabled configs, set up mysql, ... the list goes on. That is except you have a &lt;code&gt;docker&lt;/code&gt; environment set up, so they can simply:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ git clone git@git.repo.url/laravel-project
$ cd laravel-project
$ docker-compose up


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and be able to start with &lt;code&gt;composer&lt;/code&gt;, &lt;code&gt;php artisan&lt;/code&gt;, and write some code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The set-up
&lt;/h2&gt;

&lt;p&gt;To demo an existing laravel app, I will be using a blank laravel app cloned from &lt;a href="https://github.com/laravel/laravel.git" rel="noopener noreferrer"&gt;https://github.com/laravel/laravel.git&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ git clone https://github.com/laravel/laravel.git
$ cd laravel
$ git checkout -b dev-env
$ cp .env.example .env


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here's how I will structure my docker environment files:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

  app
  |__bootstrap
  |__config
  |__database
  |__public
  |__resources
  |__routes
  |__run               (+)
     |__.gitkeep       (+)
  |__storage
  |__tests
  .dockerignore        (+)
  .editorconfig
  .env
  .env.example
  .gitattributes
  .gitignore
  artisan
  CHANGELOG.md
  composer.json
  docker-compose.yml   (+)
  Dockerfile           (+)
  package.json
  phpunit.xml
  readme.md
  server.php
  webpack.mix.js


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The idea is we'll be builiding the image as well as running &lt;code&gt;docker-compose&lt;/code&gt; commands from the main application folder, while &lt;code&gt;run&lt;/code&gt; folder contains necessary config and local database for development. With &lt;code&gt;docker&lt;/code&gt; volumes, we'll be able to keep the source, the &lt;code&gt;vendor&lt;/code&gt; dependencies and local development database in our host, while all the runtime (&lt;code&gt;apache&lt;/code&gt;, &lt;code&gt;php&lt;/code&gt;) are kept and manged by the container.&lt;/p&gt;

&lt;p&gt;In this article I'll explain to the best of my knowledge what each part of the set-up does. TL;DR as well as github link to list all the changes at the bottom if you just need a working version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Webserver image for Laravel
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/docker-library/php/blob/873725e57ec2fc5f2642dc0023676597bcc4bea9/7.2/stretch/apache/Dockerfile" rel="noopener noreferrer"&gt;&lt;code&gt;php-apache:7.2&lt;/code&gt;&lt;/a&gt; image from the php dockerhub has out-of-the-box configurable and functional Apache webserver running &lt;code&gt;mod_php&lt;/code&gt;, which is a great place to start with. We'll need a couple of extensions and some access control configuration to make development easier (optional). Here is the &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; php:7.2-apache&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update

&lt;span class="c"&gt;# 1. development packages&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    git &lt;span class="se"&gt;\
&lt;/span&gt;    zip &lt;span class="se"&gt;\
&lt;/span&gt;    curl &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    unzip &lt;span class="se"&gt;\
&lt;/span&gt;    libicu-dev &lt;span class="se"&gt;\
&lt;/span&gt;    libbz2-dev &lt;span class="se"&gt;\
&lt;/span&gt;    libpng-dev &lt;span class="se"&gt;\
&lt;/span&gt;    libjpeg-dev &lt;span class="se"&gt;\
&lt;/span&gt;    libmcrypt-dev &lt;span class="se"&gt;\
&lt;/span&gt;    libreadline-dev &lt;span class="se"&gt;\
&lt;/span&gt;    libfreetype6-dev &lt;span class="se"&gt;\
&lt;/span&gt;    g++

&lt;span class="c"&gt;# 2. apache configs + document root&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; APACHE_DOCUMENT_ROOT=/var/www/html/public&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-ri&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s!/var/www/html!${APACHE_DOCUMENT_ROOT}!g'&lt;/span&gt; /etc/apache2/sites-available/&lt;span class="k"&gt;*&lt;/span&gt;.conf
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-ri&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s!/var/www/!${APACHE_DOCUMENT_ROOT}!g'&lt;/span&gt; /etc/apache2/apache2.conf /etc/apache2/conf-available/&lt;span class="k"&gt;*&lt;/span&gt;.conf

&lt;span class="c"&gt;# 3. mod_rewrite for URL rewrite and mod_headers for .htaccess extra headers like Access-Control-Allow-Origin-&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;a2enmod rewrite headers

&lt;span class="c"&gt;# 4. start with base php config, then add extensions&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PHP_INI_DIR&lt;/span&gt;&lt;span class="s2"&gt;/php.ini-development"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PHP_INI_DIR&lt;/span&gt;&lt;span class="s2"&gt;/php.ini"&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;docker-php-ext-install &lt;span class="se"&gt;\
&lt;/span&gt;    bz2 &lt;span class="se"&gt;\
&lt;/span&gt;    intl &lt;span class="se"&gt;\
&lt;/span&gt;    iconv &lt;span class="se"&gt;\
&lt;/span&gt;    bcmath &lt;span class="se"&gt;\
&lt;/span&gt;    opcache &lt;span class="se"&gt;\
&lt;/span&gt;    calendar &lt;span class="se"&gt;\
&lt;/span&gt;    mbstring &lt;span class="se"&gt;\
&lt;/span&gt;    pdo_mysql &lt;span class="se"&gt;\
&lt;/span&gt;    zip

&lt;span class="c"&gt;# 5. composer&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=composer:latest /usr/bin/composer /usr/bin/composer&lt;/span&gt;

&lt;span class="c"&gt;# 6. we need a user with the same UID/GID with host user&lt;/span&gt;
&lt;span class="c"&gt;# so when we execute CLI commands, all the host file's ownership remains intact&lt;/span&gt;
&lt;span class="c"&gt;# otherwise command from inside container will create root-owned files and directories&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; uid&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;useradd &lt;span class="nt"&gt;-G&lt;/span&gt; www-data,root &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nv"&gt;$uid&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; /home/devuser devuser
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /home/devuser/.composer &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; devuser:devuser /home/devuser


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Starting with the webserver itself, &lt;code&gt;php-apache&lt;/code&gt; image by default set document root to &lt;code&gt;/var/www/html&lt;/code&gt;. However since laravel &lt;code&gt;index.php&lt;/code&gt; is inside &lt;code&gt;/var/www/html/public&lt;/code&gt;, we need to edit the apache config as well as sites-available. We'll also enable &lt;code&gt;mod_rewrite&lt;/code&gt; for url matching and &lt;code&gt;mod_headers&lt;/code&gt; for configuring webserver headers.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; APACHE_DOCUMENT_ROOT=/var/www/html/public&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-ri&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s!/var/www/html!${APACHE_DOCUMENT_ROOT}!g'&lt;/span&gt; /etc/apache2/sites-available/&lt;span class="k"&gt;*&lt;/span&gt;.conf
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-ri&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s!/var/www/!${APACHE_DOCUMENT_ROOT}!g'&lt;/span&gt; /etc/apache2/apache2.conf /etc/apache2/conf-available/&lt;span class="k"&gt;*&lt;/span&gt;.conf


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Moving onto &lt;code&gt;php&lt;/code&gt; configuration, we start by using the provded &lt;code&gt;php.ini&lt;/code&gt;, then add a couple of extensions via &lt;code&gt;docker-php-ext-install&lt;/code&gt;. The order of doing these tasks are not important (&lt;code&gt;php.ini&lt;/code&gt; won't be overwritten) since the configs that loads each extensions are kept in separate files.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;composer&lt;/code&gt;, what we're doing here is fetching the &lt;code&gt;composer&lt;/code&gt; binary located at &lt;code&gt;/usr/bin/composer&lt;/code&gt; from the &lt;a href="https://github.com/composer/docker/blob/ebbb9efd87b78cf9b837f97105bcb6c5f0ee44ef/1.8/Dockerfile" rel="noopener noreferrer"&gt;&lt;code&gt;composer:latest&lt;/code&gt;&lt;/a&gt; docker image. Obviously you can specify any other version you want in the tag, instead of &lt;code&gt;latest&lt;/code&gt;. This is part of docker's multi-stage build feature.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=composer:latest /usr/bin/composer /usr/bin/composer&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Final steps are optional. Since we're going to mount the application source code from host into the container for development, any command run from within the container CLI shouldn't affect host files/folder ownership. This is helpful for configs and such generated by &lt;code&gt;php artisan&lt;/code&gt;. Here I'm using &lt;code&gt;ARG&lt;/code&gt; to let other team members set their own &lt;code&gt;uid&lt;/code&gt; that matches their host user &lt;code&gt;uid&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; uid&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;useradd &lt;span class="nt"&gt;-G&lt;/span&gt; www-data,root &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nv"&gt;$uid&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; /home/devuser devuser
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /home/devuser/.composer &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; devuser:devuser /home/devuser


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;docker-compose.yml&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Webserver is set. Now we just need to bring a database container in using a &lt;code&gt;docker-compose&lt;/code&gt; config&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.5'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;laravel-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.'&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${UID}&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;laravel-app&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;APACHE_RUN_USER=#${UID}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;APACHE_RUN_GROUP=#${UID}&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/var/www/html&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8000:80&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;aliases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;laravel-app&lt;/span&gt;

  &lt;span class="na"&gt;mysql-db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:5.7&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql-db&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./run/var:/var/lib/mysql&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_ROOT_PASSWORD=securerootpassword&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_DATABASE=db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_USER=dbuser&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_PASSWORD=secret&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;aliases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend-network&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A few things to go through here. First of all for the laravel container:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;build:context&lt;/code&gt; refers to the &lt;code&gt;Dockerfile&lt;/code&gt; that we just written, kept in the same directory as &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;args&lt;/code&gt; is for the &lt;code&gt;uid&lt;/code&gt; I mentioned above. We'll write &lt;code&gt;UID&lt;/code&gt; value in the app &lt;code&gt;.env&lt;/code&gt; file to let &lt;code&gt;docker-compose&lt;/code&gt; pick it up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

...
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

UID=1000


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;APACHE_RUN_USER&lt;/code&gt; and &lt;code&gt;APACHE_RUN_GROUP&lt;/code&gt; ENV variables comes with &lt;code&gt;php-apache&lt;/code&gt;. By doing this, files generated by the webserver will also have consistent ownership.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;volumes&lt;/code&gt; directive tells &lt;code&gt;docker&lt;/code&gt; to mount the host's app source code into &lt;code&gt;/var/www/html&lt;/code&gt; - which is consistent with &lt;code&gt;apache&lt;/code&gt; configuration. This enables any change from host files be reflected in the container. Commands such as &lt;code&gt;composer require&lt;/code&gt; will add &lt;code&gt;vendor&lt;/code&gt; to host, so we won't need to install dependencies everytime container is brought down and up again.&lt;/li&gt;
&lt;li&gt;If you are building container for CI / remote VM envrionment however, you'll need to add the source files into the container pre-build. For example:
```Dockerfile
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;COPY . /var/www/html&lt;br&gt;
RUN cd /var/www/html &amp;amp;&amp;amp; composer install &amp;amp;&amp;amp; php artisan key:generate&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- `ports` is optional, leave out if you're fine with running it under port 80. Alternatively, it can be configurable using `.env` similar to build args:
```yaml


ports:
  - ${HOST_PORT}:80


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

HOST_PORT=8080


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;networks&lt;/code&gt; with &lt;code&gt;aliases&lt;/code&gt; is also optional. By default, &lt;code&gt;docker-compose&lt;/code&gt; create a &lt;code&gt;default&lt;/code&gt; network prefixed with the parent folder name to connect all the services specified in &lt;code&gt;docker-compose.yml&lt;/code&gt;. However if you have a development of more than 1 &lt;code&gt;docker-compose&lt;/code&gt;, specifying &lt;code&gt;networks&lt;/code&gt; name like this allow you to join it from the other &lt;code&gt;docker-compose.yml&lt;/code&gt; files. &lt;code&gt;another-app&lt;/code&gt; here will be able to reach &lt;code&gt;laravel-app&lt;/code&gt; and vice versa, using the specified &lt;code&gt;aliases&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;another-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;aliases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;another-app&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend-network&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now moving onto &lt;code&gt;mysql&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/docker-library/mysql/blob/bb7ea52db4e12d3fb526450d22382d5cd8cd41ca/5.7/Dockerfile" rel="noopener noreferrer"&gt;&lt;code&gt;mysql:5.7&lt;/code&gt;&lt;/a&gt; is very configurable and just works well out-of-the-box. So we won't need to extend it.&lt;/li&gt;
&lt;li&gt;Simply pick up the &lt;code&gt;.env&lt;/code&gt; set in laravel app to set username and password for the db user:
```yaml
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MYSQL_ROOT_PASSWORD=securerootpassword&lt;/li&gt;
&lt;li&gt;MYSQL_DATABASE=${DB_DATABASE}&lt;/li&gt;
&lt;li&gt;MYSQL_USER=${DB_USERNAME}&lt;/li&gt;
&lt;li&gt;MYSQL_PASSWORD=${DB_PASSWORD}&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Also make sure `.env DB_HOST` set to what mysql-db service name, or its aliases:
`.env`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DB_HOST=mysql-db&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Ideally you want to keep database changes in the repository, using a series of migrations and seeders. However if you want to start the mysql container with an existing SQL dump, simply mount the SQL file:
```yaml


volumes:
   - ./run/var:/var/lib/mysql
   - ./run/dump/init.sql:/docker-entrypoint-initdb.d/init.sql


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;volumes&lt;/code&gt;, we're keeping the database locally under &lt;code&gt;run/var&lt;/code&gt;, since any data written by &lt;code&gt;mysqld&lt;/code&gt; is inside the container's &lt;code&gt;/var/lib/mysql&lt;/code&gt;. We just need to ignore the local database in both &lt;code&gt;.gitignore&lt;/code&gt; and &lt;code&gt;.dockerignore&lt;/code&gt; (for build context):&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;.gitignore&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

/node_modules
/public/hot
/public/storage
/storage/*.key
/vendor
.env
.phpunit.result.cache
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log

run/var


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;.dockerignore&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

run/var


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Up and Running
&lt;/h2&gt;

&lt;p&gt;Now let's build the environment, and get it up running. We'll also be installing composer dependencies as well as some artisan command.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ docker-compose build &amp;amp;&amp;amp; docker-compose up -d &amp;amp;&amp;amp; docker-compose logs -f
Creating network "backend-network" with the default driver
Creating mysql-db    ... done
Creating laravel-app ... done
Attaching to laravel-app, mysql-db
...


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once all the containers are up and running, we can check them by &lt;code&gt;docker ps&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                  NAMES
c1ae3002d260        laravel_laravel-app   "docker-php-entrypoi…"   4 minutes ago       Up 4 minutes        0.0.0.0:8000-&amp;gt;80/tcp   laravel-app
6f6546224051        mysql:5.7             "docker-entrypoint.s…"   4 minutes ago       Up 4 minutes        3306/tcp               mysql-db


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Composer and artisan:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ docker exec -it laravel-app bash -c "sudo -u devuser /bin/bash"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

devuser@c1ae3002d260:/var/www/html$ composer install
...
Generating optimized autoload files
&amp;gt; Illuminate\Foundation\ComposerScripts::postAutoloadDump
&amp;gt; @php artisan package:discover --ansi
Discovered Package: beyondcode/laravel-dump-server
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

devuser@c1ae3002d260:/var/www/html$ php artisan key:generate
Application key set successfully.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

devuser@c1ae3002d260:/var/www/html$ php artisan migrate
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

devuser@c1ae3002d260:/var/www/html$ php artisan make:auth
Authentication scaffolding generated successfully.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With hostfile:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

127.0.0.1       laravel-app.local


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We're all set!&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6sjhqe14hxncatoip5n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6sjhqe14hxncatoip5n.png" alt="App Screenshot"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9xo111cj5n06ybptl06y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9xo111cj5n06ybptl06y.png" alt="App Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Helper scripts (optional)
&lt;/h2&gt;

&lt;p&gt;From time to time, I want to be able to quickly run CLI commands (&lt;code&gt;composer&lt;/code&gt;, &lt;code&gt;artisan&lt;/code&gt;, etc.) without having to type &lt;code&gt;docker exec&lt;/code&gt; everytime. So here are some bash scripts I made wrapping around &lt;code&gt;docker exec&lt;/code&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;container&lt;/code&gt;
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; laravel-app bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"sudo -u devuser /bin/bash"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Running &lt;code&gt;./container&lt;/code&gt; takes you inside the &lt;code&gt;laravel-app&lt;/code&gt; container under user &lt;code&gt;uid(1000)&lt;/code&gt; (same with host user)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ ./container
devuser@8cf37a093502:/var/www/html$


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;db&lt;/code&gt;
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; mysql-db bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"mysql -u dbuser -psecret db"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Running &lt;code&gt;./db&lt;/code&gt; will connect to your database container's daemon using mysql client.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ ./db
mysql&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;composer&lt;/code&gt;
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"composer &lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; laravel-app bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"sudo -u devuser /bin/bash -c &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Run any &lt;code&gt;composer&lt;/code&gt; command, example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ ./composer dump-autoload
Generating optimized autoload files&amp;gt; Illuminate\Foundation\ComposerScripts::postAutoloadDump
&amp;gt; @php artisan package:discover --ansi
Discovered Package: beyondcode/laravel-dump-server
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
Generated optimized autoload files containing 3527 classes


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;php-artisan&lt;/code&gt;
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"php artisan &lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; laravel-app bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"sudo -u devuser /bin/bash -c &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Run &lt;code&gt;php artisan&lt;/code&gt; commands, example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ ./php-artisan make:controller BlogPostController --resource
php artisan make:controller BlogPostController --resource
Controller created successfully.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;phpunit&lt;/code&gt;
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"vendor/bin/phpunit &lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; laravel-app bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"sudo -u devuser /bin/bash -c &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Run &lt;code&gt;./vendor/bin/phpunit&lt;/code&gt; to execute tests, example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ ./phpunit --group=failing
vendor/bin/phpunit --group=failing
PHPUnit 7.5.8 by Sebastian Bergmann and contributors.



Time: 34 ms, Memory: 6.00 MB

No tests executed!


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/veevidify/laravel-apache-docker" rel="noopener noreferrer"&gt;Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/veevidify/laravel-apache-docker/commit/48933bd10c6da6c1d3addb1b1dfc6d9b7ec4d49b" rel="noopener noreferrer"&gt;commit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Dockerfile&lt;/code&gt; consists of basic apache document root config, mod_rewrite and mod_header, composer and sync container's uid with host uid.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt; boots up &lt;code&gt;php-apache&lt;/code&gt; (mount app files) and &lt;code&gt;mysql&lt;/code&gt; (mount db files), using &lt;code&gt;networks&lt;/code&gt; to interconnect.&lt;/p&gt;

&lt;p&gt;Use the environment:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ docker-compose build &amp;amp;&amp;amp; docker-compose up -d &amp;amp;&amp;amp; docker-compose logs -f
$ ./composer install
$ ./php-artisan key:generate


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>beginners</category>
      <category>laravel</category>
      <category>docker</category>
      <category>dockercompose</category>
    </item>
  </channel>
</rss>
