Konfiguration af vores arbejdsmiljø
Konfiguration af PHP-beholderen
Konfiguration af Nginx-beholderen
Konfiguration af MySQL-beholderen
Opbygning af vores applikation
Konklusion
PHP-applikationer er normalt sammensat af en webserver, et relationsdatabasesystem og selve sprogfortolkeren. I denne tutorial vil vi udnytte en fuld PHP-applikationsstak ved hjælp af docker. Dette er en dybdegående tutorial, hvor vi skal bygge og orkestrere containere til Nginx (webserveren), MySQL (databasesystemet) og PHP.
Af hensyn til denne vejledning vil vi skrive en simpel applikation, der læser en liste over byer fra en database og viser den på en webside, på denne måde vil vi demonstrere en grundlæggende, men fungerende, PHP-applikation.
Denne vejledning antager, at du allerede har Docker-CE installeret og i det mindste et minimalt kendskab til docker. For den sags skyld kan du gennemgå følgende tutorials:
Konfiguration af vores arbejdsmiljø
En real life docker-baseret applikation vil typisk være sammensat af flere containere. Håndtering af disse manuelt kan nemt blive ret rodet og besværligt. Det er her docker-compose kommer ind i billedet. Det hjælper dig med at administrere en række containere gennem en simpel yaml
konfigurationsfil.
Installer docker-compose.
curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
Opret en mappe til at indeholde alle de nødvendige filer i dette eksempel og derefter cd
ind i den. Fra nu af er dette vores arbejdsmappe, og hver kommando vil blive udført inde i denne mappe, og hver sti vil blive refereret til den. Denne mappe kan senere henvises til som WORKING_DIR
.
mkdir ~/docker
cd ~/docker
Opret nu yderligere tre mapper.
mkdir php nginx app
Den php
mappe er, hvor vi vil bygge vores brugerdefinerede PHP billede, nginx
vil mappen holde de nødvendige filer til vores brugerdefinerede nginx image og den app
mappe er, hvor vi vil lægge kildekoden og konfiguration af vores stikprøve ansøgning.
Konfiguration af PHP-beholderen
I dette eksempel skal vi bruge php-fpm
til at oprette forbindelse til Nginx-webserveren. Vi vil bruge det officielle PHP-basebillede. Vi skal dog også installere og aktivere nogle udvidelser, så vi kan få adgang til databasen. php
Opret en fil med navnet inde i mappen, Dockerfile
og læg følgende indhold ind i den.
FROM php:7.1-fpm-alpine3.4
RUN apk update --no-cache \
&& apk add --no-cache $PHPIZE_DEPS \
&& apk add --no-cache mysql-dev \
&& docker-php-ext-install pdo pdo_mysql
Bemærk, at vi bruger Alpine-versionen af det officielle PHP-billede. Alpine er en meget lille distribution rettet mod containere ved at give meget mindre fodspor. Bemærk også brugen af kommandoen docker-php-ext-install
, det officielle PHP-billede giver denne kommando for at lette processen med at installere og konfigurere PHP-udvidelser.
Lad os nu bygge dette Docker-billede ved at udstede følgende (inde i vores WORKING_DIR
):
docker build -t vultr-php php/
den docker-compose.yml
fil
Som allerede nævnt docker-compose
giver det dig mulighed for at administrere et antal containere gennem en simpel konfigurationsfil. Denne konfigurationsfil hedder typisk docker-compose.yml
. Opret denne fil inde i app
mappen.
touch app/docker-compose.yml
Indsæt nu følgende indhold i denne fil.
version: '2'
services:
php:
image: vultr-php
volumes:
- ./:/app
working_dir: /app
Vi vil forklare denne syntaks. Bemærk først den første linje.
version: '2'
Dette angiver versionen af den anvendte docker-compose.yml
konfigurationsfil. Den næste linje specificerer tjenesterne, eller med andre ord, de containere, der skal klargøres.
services:
php:
image: vultr-php
volumes:
- ./:/app
working_dir: /app
Bemærk, at hver tjeneste har en specifik nøgle inde i services
blokken. Det navn, der er angivet her, vil blive brugt til at henvise til denne specifikke container senere. Bemærk også, at inde i php
konfigurationen definerer vi det billede, der bruges til at køre containeren (dette er det billede, vi byggede tidligere). Vi definerer også en volumenmapping.
volumes:
- ./:/app
Dette fortæller, docker-compose
at den aktuelle mappe ( ./
) skal tilknyttes /app
mappen inde i containeren. Den sidste linje sætter /app
mappen inde i containeren som arbejdsbiblioteket, hvilket betyder, at dette er mappen, hvorfra alle fremtidige kommandoer inde i en container som standard udføres.
Vi kan nu orkestrere vores containere.
cd ~/docker/app
docker-compose up -d
Du kan køre følgende kommando for at sikre, at PHP-beholderen blev udført:
docker ps
Sådan udføres kommandoer inde i containerne
Stadig inde i app
mappen kan vi køre enhver kommando inde i en defineret servicecontainer ved hjælp af docker-compose
kommandoen.
docker-compose exec [service] [command]
Den [service]
pladsholder refererer til tjenesten tasten. I vores tilfælde var dette php
. Lad os køre en kommando inde i containeren for at tjekke vores PHP-version.
docker-compose exec php php -v
Du vil se følgende output.
PHP 7.1.14 (cli) (built: Feb 7 2018 00:40:45) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
Konfiguration af Nginx-beholderen
Ligesom PHP-containeren skal vi oprette et brugerdefineret billede til webserveren. Men i dette tilfælde skal vi blot levere en konfiguration til vores virtual host
. Sørg for at du er inde i vores WORKING_DIR
og opret en Dockerfile
inde i nginx
mappen:
cd ~/docker
touch nginx/Dockerfile
Læg nu følgende indhold ind i dette Dockerfile
:
FROM nginx:1.13.8-alpine
COPY ./default.conf /etc/nginx/conf.d/default.conf
Vi bruger standard Nginx-billedet baseret på Alpine. På denne Docker-fil kopierer vi simpelthen en konfigurationsfil til vores applikationsopsætning. Før du bygger dette billede, skal du oprette en konfigurationsfil.
touch nginx/default.conf
Udfyld det nu med dette indhold.
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /app;
index index.php;
#server_name server_domain_or_IP;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri /index.php =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Bemærk, at på fastcgi_pass php:9000
linjen henviser vi til PHP-beholderen ved dets navn inde i service
blokken af docker-compose.yml
konfigurationsfilen. docker-compose
Opretter internt et netværk og tildeler tjenestenavnet som værtsnavn til hver af de definerede tjenester. Vi kan nu bygge Nginx-billedet.
docker build -t vultr-nginx nginx/
Opdatering docker-compose.yml
Opdater nu app/docker-compose.yml
filen.
version: '2'
services:
php:
image: vultr-php
volumes:
- ./:/app
working_dir: /app
web:
image: vultr-nginx
volumes:
- ./:/app
depends_on:
- php
ports:
- 80:80
Vi har kun tilføjet en ny tjeneste. Konfigurationen er næsten den samme, bortset fra følgende.
depends_on:
- php
ports:
- 80:80
Once the Nginx container needs the PHP service to be fully initialized, we force this requirement in the depends_on
option.
The ports
configuration key maps a host port to a container port, here we map the port 80
in the host to the port 80
in
the container.
Now create a file called index.php
inside the app
folder and put the following in it.
<?php phpinfo();
Make sure the port 80
is accessible through your firewall and execute the following.
cd ~/docker/app
docker-compose up -d
Once again, double check that the service is up.
docker ps
Open a browser and access [vultr-instance-ip]
. You may find out your Vultr instance IP address by running the following.
hostname -I
You will see the PHP info page.
Configuring the MySQL container
Det officielle MySQL-billede giver dig mulighed for at konfigurere containeren gennem simple miljøvariabler. Dette kan gøres med en environment
mulighed inde i serviceblokdefinitionen. Opdater ~/docker/app/docker-compose.yml
filen til følgende.
version: '2'
services:
php:
image: vultr-php
volumes:
- ./:/app
working_dir: /app
web:
image: vultr-nginx
volumes:
- ./:/app
depends_on:
- php
ports:
- 80:80
mysql:
image: mysql:5.7.21
volumes:
- ./:/app
- dbdata:/var/lib/mysql
environment:
- MYSQL_DATABASE=world
- MYSQL_ROOT_PASSWORD=root
working_dir: /app
volumes:
dbdata:
Nu har vi defineret en ny service til databasen. Læg mærke til linjen dbdata:/var/lib/mysql
. Dette monterer stien på containeren /var/lib/mysql
til en vedvarende volumen, der administreres af Docker, på denne måde bevarer databasedataene, efter at containeren er fjernet. Denne volumen skal defineres i en blok på øverste niveau, som du kan se i slutningen af filen.
Før vi orkestrerer vores nye konfiguration, lad os downloade et eksempel på en MySQL-database. Den officielle MySQL-dokumentation
indeholder nogle eksempeldatabaser. Vi vil bruge den velkendte verdensdatabase. Denne database giver en liste over lande og byer. For at downloade denne prøve skal du udføre følgende i vores app-mappe.
curl -L http://downloads.mysql.com/docs/world.sql.gz -o world.sql.gz
gunzip world.sql.gz
Lad os nu orkestrere vores containere.
docker-compose up -d
Som du måske allerede har bemærket, starter docker-compose up
kommandoen kun de containere, der ikke allerede er startet. Den tjekker for forskellene mellem din docker-compose.yml
fil og den aktuelle konfiguration af kørende containere.
En gang mere skal du kontrollere, at MySQL-beholderen er startet.
docker ps
Udfyld nu verdensdatabasen.
docker-compose exec -T mysql mysql -uroot -proot world < world.sql
Du kan kontrollere, at databasen er udfyldt ved at vælge data direkte fra databasen. Få først adgang til MySQL-prompten inde i containeren.
docker-compose exec mysql mysql -uroot -proot world
Kør følgende i MySQL-prompten.
select * from city limit 10;
Du vil se en liste over byer. Afslut nu MySQL-prompten.
mysql> exit
Opbygning af vores applikation
Nu hvor alle de nødvendige beholdere er oppe at køre, kan vi fokusere på vores eksempelapplikation. Opdater
app/index.php
filen til følgende.
<?php
$pdo = new PDO('mysql:host=mysql;dbname=world;charset=utf8', 'root', 'root');
$stmt = $pdo->prepare("
select city.Name, city.District, country.Name as Country, city.Population
from city
left join country on city.CountryCode = country.Code
order by Population desc
limit 10
");
$stmt->execute();
$cities = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Vultr Rocks!</title>
</head>
<body>
<h2>Most Populous Cities In The World</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Country</th>
<th>District</th>
<th>Population</th>
</tr>
</thead>
<tbody>
<?php foreach($cities as $city): ?>
<tr>
<td><?=$city['Name']?></td>
<td><?=$city['Country']?></td>
<td><?=$city['District']?></td>
<td><?=number_format($city['Population'], 0)?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
</body>
</html>
Hvis du åbner [vultr-instance-ip]
i en webbrowser, vil du se en liste over de mest folkerige byer i verden. Tillykke, du har implementeret et fuldt fungerende PHP-program ved hjælp af docker.
Konklusion
I denne tutorial har jeg demonstreret trin for trin, hvordan man konfigurerer en fuldt fungerende PHP-applikation. Vi byggede brugerdefinerede billeder til PHP og Nginx og konfigurerede docker-compose til at orkestrere vores containere. På trods af at den er meget grundlæggende og enkel, afspejler denne opsætning et scenarie fra det virkelige liv.
I denne guide har vi bygget og tagget vores billeder lokalt. For en mere fleksibel opsætning kan du skubbe disse billeder til et docker-register . Du kan skubbe til det officielle docker-register eller endda opsætte dit eget docker-register. Under alle omstændigheder vil dette give dig mulighed for at bygge dine billeder på én vært og bruge dem på en anden.
For en mere detaljeret brug af docker-compose
, skal du henvise til den officielle dokumentation .
Afhængigt af dine applikationskrav og den PHP-ramme, du bruger, vil du måske tilføje flere udvidelser. Dette kan nemt gøres ved at ændre det Dockerfile
brugte til at bygge vores brugerdefinerede PHP-billede. Nogle udvidelser har dog brug for ekstra afhængigheder for at blive installeret i containeren. Du bør henvise til listen over udvidelser i den
officielle PHP-dokumentation for at gennemgå de grundlæggende krav til hver udvidelse.