-
Notifications
You must be signed in to change notification settings - Fork 0
/
Developing_in_PHP_Using_Docker.html
418 lines (313 loc) · 15.2 KB
/
Developing_in_PHP_Using_Docker.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>Developing_in_PHP_Using_Docker</title>
<style type="text/css">
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
margin: 0;
padding: 0;
}
body {
font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
line-height: 18px;
color: #737373;
background-color: white;
margin: 10px 13px 10px 13px;
}
table {
margin: 10px 0 15px 0;
border-collapse: collapse;
}
td,th {
border: 1px solid #ddd;
padding: 3px 10px;
}
th {
padding: 5px 10px;
}
a {
color: #0069d6;
}
a:hover {
color: #0050a3;
text-decoration: none;
}
a img {
border: none;
}
p {
margin-bottom: 9px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: #404040;
line-height: 36px;
}
h1 {
margin-bottom: 18px;
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 13px;
}
hr {
margin: 0 0 19px;
border: 0;
border-bottom: 1px solid #ccc;
}
blockquote {
padding: 13px 13px 21px 15px;
margin-bottom: 18px;
font-family:georgia,serif;
font-style: italic;
}
blockquote:before {
content:"\201C";
font-size:40px;
margin-left:-10px;
font-family:georgia,serif;
color:#eee;
}
blockquote p {
font-size: 14px;
font-weight: 300;
line-height: 18px;
margin-bottom: 0;
font-style: italic;
}
code, pre {
font-family: Monaco, Andale Mono, Courier New, monospace;
}
code {
background-color: #fee9cc;
color: rgba(0, 0, 0, 0.75);
padding: 1px 3px;
font-size: 12px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
pre {
display: block;
padding: 14px;
margin: 0 0 18px;
line-height: 16px;
font-size: 11px;
border: 1px solid #d9d9d9;
white-space: pre-wrap;
word-wrap: break-word;
}
pre code {
background-color: #fff;
color:#737373;
font-size: 11px;
padding: 0;
}
sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}
* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {
width: 854px;
margin:10px auto;
}
}
@media print {
body,code,pre code,h1,h2,h3,h4,h5,h6 {
color: black;
}
table, pre {
page-break-inside: avoid;
}
}
</style>
</head>
<body>
<h1 id="toc_0">Developing in PHP Using Docker</h1>
<p><em>Brian Leach, Steelray Software</em></p>
<p><img src="boxes.png" alt="Little Boxes . . ."></p>
<p>When I first starting developing web applications, I used FTP and other methods to update a "staging" version of my website. This was a pain, so I was happy when tools like XAMPP came along which bundled my technology stack (Apache, MySQL, PHP) to make it faster and easier to test and debug locally.</p>
<p>I used XAMPP for many years, until I discovered Vagrant. </p>
<p>Vagrant made it fairly easy and quick to set up a virtual server with the technology stack that I needed, so I thought I'd be a Vagrant user for quite some time.</p>
<p>Until I came across container technology, specifically Docker.</p>
<h2 id="toc_1">What is Docker?</h2>
<p>Containers allow developers to package applications with all of the parts it needs and little else. With Vagrant, five virtual machines gave you five copies of Linux. With containers like Docker, each container shares the same operating system: the one on your host. The upside: better performance and a smaller footprint.</p>
<h2 id="toc_2">This Tutorial</h2>
<p>In this tutorial, I'll show you how simple it is to set up Docker on a Mac and debug and test a PHP/MySQL web application.</p>
<p>You'll notice a few really nice benefits of using Docker:</p>
<ol>
<li>It won't take very long to set up.</li>
<li>It won't use a lot of space.</li>
<li>You'll make no changes to the actual container. You won't need to ssh into it for any reason.</li>
<li>The container will be quite disposable. Meaning: you can delete it and create a new one without losing anything.</li>
<li>You can use the tools on your Mac -- your IDE, your mysql client, etc.</li>
</ol>
<h2 id="toc_3">Step 1: Install Docker for Mac</h2>
<p>Visit <a href="https://www.docker.com/docker-mac">https://www.docker.com/docker-mac</a> and download Docker for Mac. It's free!</p>
<h2 id="toc_4">Step 2: Build and Extract a Docker Compose File</h2>
<p>We're going to take a shortcut in creating our Docker configuration -- an extremely helpful online tool I found at <strong>phpdocker.io</strong>. The tool allows you to fill out a simple form and generate the config files that you'll need to build your containers.</p>
<p>Visit <a href="https://phpdocker.io/generator">https://phpdocker.io/generator</a>. Fill in the following fields:</p>
<ul>
<li><em>Project Name</em> - Call it whatever you like. Don't use spaces. Example: <code>docker-web</code></li>
<li><em>Base port</em>: Use something you're not already using on your local machine. Example: <code>8022</code>. Whatever you use, you'll use later when you browse to your site, e.g. <code>http://localhost:8022</code></li>
<li><em>Extensions</em>: Select <code>mysql</code> and <code>xdebug</code>.</li>
<li><p>Turn on the switch for mysql (or MariaDB or Postgres) if you need a database.</p>
<ul>
<li>If you do so, you'll be asked for account names and passwords. It doesn't matter what they are right now, so I'm filling in random values.</li>
<li>root user pass: PestoMadnessFestival</li>
<li>app database name: MyAwesomeDb </li>
<li>app database username: victortequila</li>
<li>app database password: DropIcyBackpacks</li>
</ul></li>
<li><p>Click <em>Generate Project Archive</em>. A zip file will download.</p></li>
<li><p>Move the file to the location where you want the sandbox. You do <em>not</em> need to create a new directory for it. The root directory in the zip file will be whatever you named your project. I moved mine into ~/Code</p></li>
<li><p>Extract the zip file.</p></li>
</ul>
<p>Here's what you'll have in your sandbox after you extract the file:</p>
<p><img src="dir_structure.png" alt="Directory Structure"></p>
<h3 id="toc_5">docker-compose.yml</h3>
<p>docker-compose is a tool that lets you define multiple Docker containers in one file. The contents of our docker-compose.yml file:</p>
<div><pre><code class="language-none">###############################################################################
# Generated on phpdocker.io #
###############################################################################
version: "3.1"
services:
mysql:
image: mysql:8.0
container_name: docker-web-mysql
working_dir: /application
volumes:
- .:/application
environment:
- MYSQL_ROOT_PASSWORD=PestoMadnessFestival
- MYSQL_DATABASE=MyAwesomeDb
- MYSQL_USER=victortequila
- MYSQL_PASSWORD=DropIcyBackpacks
ports:
- "8024:3306"
webserver:
image: nginx:alpine
container_name: docker-web-webserver
working_dir: /application
volumes:
- .:/application
- ./phpdocker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- "8022:80"
php-fpm:
build: phpdocker/php-fpm
container_name: docker-web-php-fpm
working_dir: /application
volumes:
- .:/application
- ./phpdocker/php-fpm/php-ini-overrides.ini:/etc/php/7.1/fpm/conf.d/99-overrides.ini
</code></pre></div>
<p>We have 3 entries in the services section: mysql, webserver, and php-fpm. These are pretty self-explanatory: one container is created for the database, one for the web server (nginx), and one for PHP.</p>
<p><strong>image</strong> specifies the image to start the container from. Since the image doesn't currently exist, Docker will pull it from a public repository. Note that <strong>php-fpm</strong> has a <strong>build</strong> item instead. In this case, a path is provided to a build context. If you follow that directory path, you'll see a separate Dockerfile.</p>
<p><strong>container_name</strong> allows you to override the container name that Docker would otherwise generate for you.</p>
<p><strong>working_dir</strong> specifies the working directory of the container that is created. In all 3 containers, the path is /application.</p>
<p><strong>volumes</strong> specifies file and directory mappings from your machine (e.g. your Mac) to the container's file system. The line:</p>
<div><pre><code class="language-none">.:/application</code></pre></div>
<p>is shorthand syntax for mapping the current directory on your Mac (where the docker-compose.yml is) to the directory /application in your container.</p>
<p>Note that the webserver container adds a second mapping: </p>
<div><pre><code class="language-none">./phpdocker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf</code></pre></div>
<p>The nginx.conf file that you unzipped becomes the actual configuration file for the webserver. This lets you edit it locally on your Mac.</p>
<p><strong>environment</strong> lets you set environment variables that will be active inside the container. In the mysql container, you can see the database information we set on phpdocker.io. </p>
<p>Finally, <strong>ports</strong> lets you specify a port mapping from your local host to your container. In the webserver container, we can see that port 80 is mapped to port 8022 on our Mac. You can also see that the standard port for mysql (3306) is mapped to port 8024 on our Mac. This allows you to use the database using a local client.</p>
<h4 id="toc_6">A Quick Change to the location of the database . . .</h4>
<p>By default, our database will be stored on the container in <code>/var/lib/mysql</code>. Because we want our containers to be completely disposable, let's map that directory on the container to one on our Mac. For example, /Users/yourname/mysql. Create that folder, and in the mysql service section of docker-compose.yml, change the mapping from: </p>
<div><pre><code class="language-none">volumes:
- .:/application</code></pre></div>
<p>to:</p>
<div><pre><code class="language-none">volumes:
- /Users/yourname/mysql:/var/lib/mysql</code></pre></div>
<h2 id="toc_7">Step 3: Running the Container</h2>
<p>docker-compose is the command you use for running multiple-container Docker applications. To run the containers, issue the following command from your sandbox directory:</p>
<div><pre><code class="language-none">docker-compose up -d</code></pre></div>
<p>The -d option (for detached, but it could also stand for daemon) tells the command to run in the background.</p>
<p>The first time you run the command will be different from subsequent runs. Because it hasn't been run before, some software needs to be downloaded, and in the case of the php-fpm container, built.</p>
<h2 id="toc_8">Step 4: Sanity Test</h2>
<p>Before we run a quick test, if you take a look at the nginx config file, located in docker-web/phpdocker/nginx/nginx.conf, you'll see a pretty standard setup. I'll call attention to one line:</p>
<div><pre><code class="language-none">root /application/public;</code></pre></div>
<p>In the container, it specifies that the root directory of the website is /<code>application/public</code>. Because /application maps to our sandbox directory (remember that from the docker-compose.yml file?), that means we can create a directory called public in our sandbox and that will be the root of the website.</p>
<p>Let's test our newly built containers with a simple php file.</p>
<div><pre><code class="language-none">$ mkdir public
$ cd public
$ cat > index.php
<?php echo "Hello!"; ?>
(ctrl-d to exit)
$ </code></pre></div>
<p>And when we browse to the root of the website, we see:</p>
<p><img src="sanity_test.png" alt="Sanity Test"></p>
<h2 id="toc_9">Step 5: Link to Your Real Website</h2>
<p>Now that we have our containers up and running, let's run with our real application.</p>
<p>We don't want to copy our application into our docker-web directory, so we'll simply change the mappings in our docker-compose.yml file:</p>
<p>In the webserver and php-fpm containers, we'll change the mapping from: </p>
<div><pre><code class="language-none">- .:/application</code></pre></div>
<p>to:</p>
<div><pre><code class="language-none">- [Path-to-your-website-files]:/application/public</code></pre></div>
<p>Now we have to restart the containers:</p>
<div><pre><code class="language-none">docker-compose restart</code></pre></div>
<p>If all went well, you can browse to <code>localhost:8022</code> and see your web application.</p>
<h2 id="toc_10">Step 6: Load Your Database</h2>
<p>In the docker-compose.yml, mysql is mapped from the default (3306) to port 8024 on my Mac. So, we can connect to it from mysql on the Mac:</p>
<div><pre><code class="language-none">mysql -uroot -p -h 127.0.0.1 -P 8024
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.</code></pre></div>
<p>Remember to use the mysql root password from the docker-compose.yml file. </p>
<p>Using a backup file, it's easy enough to load the database for the application:</p>
<div><pre><code class="language-none">mysql> create database appdb;
Query OK, 1 row affected (0.00 sec)
mysql> use appdb;
Database changed
mysql> source appdb_backup.sql;</code></pre></div>
<p>And now we have a fully stocked database.</p>
<h2 id="toc_11">Step 7: Get Debugging Working</h2>
<p>Before I do any kind of development, the first thing I want to make sure of is that I can debug my code -- set breakpoints, single-step, etc.</p>
<p>When we created our container, we specified that the xdebug extension should be included in the web server. The challenge is that xdebug on the container needs to communicate with the host. The host, however, cannot be counted on to always have the same IP address. Docker for Mac provides a DNS name (<code>docker.for.mac.localhost</code>) which will always resolve to the internal IP address used by the host. Pretty cool, right?</p>
<p>We have to make a slight change to the PHP config file. In the <code>phpdocker/php-fpm/php-ini-overrides.ini</code>, we add 3 lines:</p>
<div><pre><code class="language-none">xdebug.remote_enable=1
xdebug.remote_host=docker.for.mac.localhost
xdebug.remote_connect_back=0</code></pre></div>
<p><strong>Important:</strong> After changing the file, be sure to restart the container by running <code>docker-compose restart</code>.</p>
<h3 id="toc_12">Example: Debugging in PHPStorm</h3>
<p>To set up debugging, I'll use PHPStorm as an example, but the principles are the same for other IDEs or debuggers.</p>
<h4 id="toc_13">Run/Debug Configuration</h4>
<p><img src="run_config.png" alt="PHPStorm Run/Debug Configuration"></p>
<h4 id="toc_14">Server Configuration</h4>
<p><img src="server_config.png" alt="PHPStorm Server Configuration"></p>
<h2 id="toc_15">That's It!</h2>
<p>As you can see, using Docker for your development sandbox is quick and easy, with minimal impact on your development machine. There's a lot more to explore, but this should give you a good head start on your exploration.</p>
</body>
</html>