Конфигуриране на нашата работна среда
Конфигуриране на PHP контейнера
Конфигуриране на контейнера Nginx
Конфигуриране на MySQL контейнера
Изграждане на нашето приложение
Заключение
PHP приложенията обикновено се съставят от уеб сървър, система за релационна база данни и самия езиков интерпретатор. В този урок ще използваме пълен стек от PHP приложения с помощта на docker. Това е задълбочен урок, в който ще изградим и организираме контейнери за Nginx (уеб сървъра), MySQL (системата на база данни) и PHP.
В името на този урок ще напишем просто приложение, което чете списък с градове от база данни и го показва на уеб страница, като по този начин ще демонстрираме основно, но работещо PHP приложение.
Това ръководство предполага, че вече имате инсталиран Docker-CE и поне минимални работни познания за docker. По този въпрос можете да прегледате следните уроци:
Конфигуриране на нашата работна среда
Приложението, базирано на докер в реалния живот, обикновено се състои от няколко контейнера. Ръчното им управление може лесно да стане доста объркано и тромаво. Това е мястото, където docker-compose влиза в игра. Той ви помага да управлявате редица контейнери чрез прост yaml
конфигурационен файл.
Инсталирайте 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
Създайте папка, в която да съхранявате всички необходими файлове от този пример и след това cd
в нея. Оттук нататък това е нашата работна директория и всяка команда ще се изпълнява в тази папка и всеки път ще бъде препратен спрямо нея. Тази папка може да бъде посочена по-късно като WORKING_DIR
.
mkdir ~/docker
cd ~/docker
Сега създайте още три папки.
mkdir php nginx app
В php
папката е мястото, където ще се изгражда нашия обичай PHP изображение на nginx
папката ще проведе необходимите файлове за нашия обичай Nginx образ и app
папката е мястото, където ще бъде въвеждането на изходния код и конфигурацията на нашата извадка приложение.
Конфигуриране на PHP контейнера
В този пример ще използваме php-fpm
за свързване с уеб сървъра на Nginx. Ще използваме официалното базово изображение на PHP. Въпреки това, ние също трябва да инсталираме и активираме някои разширения, за да имаме достъп до базата данни. Вътре в php
папката създайте файл с име Dockerfile
и поставете следното съдържание в него.
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
Имайте предвид, че използваме алпийската версия на официалното изображение на PHP. Alpine е много малка дистрибуция, насочена към контейнери, като осигурява много по-малки отпечатъци. Също така, имайте предвид използването на командата docker-php-ext-install
, официалното изображение на PHP предоставя тази команда, за да улесни процеса на инсталиране и конфигуриране на PHP разширения.
Сега, нека изградим това изображение на Docker, като издадем следното (вътре в нашия WORKING_DIR
):
docker build -t vultr-php php/
В docker-compose.yml
досието
Както вече споменахме, docker-compose
ви позволява да управлявате редица контейнери чрез прост конфигурационен файл. Този конфигурационен файл обикновено се нарича docker-compose.yml
. Създайте този файл в app
папката.
touch app/docker-compose.yml
Сега поставете следното съдържание в този файл.
version: '2'
services:
php:
image: vultr-php
volumes:
- ./:/app
working_dir: /app
Ще обясним този синтаксис. Първо, обърнете внимание на първия ред.
version: '2'
Това указва версията на използвания docker-compose.yml
конфигурационен файл. Следващият ред указва услугите, или с други думи, контейнерите, които трябва да бъдат предоставени.
services:
php:
image: vultr-php
volumes:
- ./:/app
working_dir: /app
Имайте предвид, че всяка услуга има специфичен ключ вътре в services
блока. Посоченото тук име ще се използва за препратка към този конкретен контейнер по-късно. Също така имайте предвид, че вътре в php
конфигурацията ние дефинираме изображението, използвано за стартиране на контейнера (това е изображението, което изградихме по-рано). Ние също така дефинираме картографиране на обема.
volumes:
- ./:/app
Това казва docker-compose
да се съпостави текущата директория ( ./
) с /app
директорията вътре в контейнера. Последният ред задава /app
папката вътре в контейнера като работна директория, което означава, че това е папката, от която по подразбиране се изпълняват всички бъдещи команди в контейнера.
Вече можем да организираме нашите контейнери.
cd ~/docker/app
docker-compose up -d
Можете да изпълните следната команда, за да сте сигурни, че PHP контейнерът е изпълнен:
docker ps
Как да изпълнявате команди вътре в контейнерите
Все още в app
папката, можем да изпълним всяка команда в дефиниран контейнер за услуги с помощта на docker-compose
командата.
docker-compose exec [service] [command]
Най- [service]
заместител се отнася до сервизния ключ. В нашия случай това беше php
. Нека изпълним команда вътре в контейнера, за да проверим нашата PHP версия.
docker-compose exec php php -v
Ще видите следния изход.
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
Конфигуриране на контейнера Nginx
Точно като PHP контейнера, трябва да създадем персонализирано изображение за уеб сървъра. Но в този случай просто трябва да предоставим конфигурация за нашия virtual host
. Уверете се, че сте вътре в нашата WORKING_DIR
и създайте Dockerfile
вътре в nginx
папката:
cd ~/docker
touch nginx/Dockerfile
Сега поставете следното съдържание в това Dockerfile
:
FROM nginx:1.13.8-alpine
COPY ./default.conf /etc/nginx/conf.d/default.conf
Ние използваме изображението по подразбиране на Nginx, базирано на Alpine. В този файл на Docker ние просто копираме конфигурационен файл в настройката на нашето приложение. Преди да създадете това изображение, създайте конфигурационен файл.
touch nginx/default.conf
Сега го попълнете с това съдържание.
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;
}
}
Имайте предвид, че на fastcgi_pass php:9000
реда препращаме PHP контейнера по неговото име в service
блока на docker-compose.yml
конфигурационния файл. Вътрешно docker-compose
създава мрежа и присвоява името на услугата като име на хост на всяка от дефинираните услуги. Вече можем да изградим изображението на Nginx.
docker build -t vultr-nginx nginx/
Актуализиране docker-compose.yml
Сега актуализирайте app/docker-compose.yml
файла.
version: '2'
services:
php:
image: vultr-php
volumes:
- ./:/app
working_dir: /app
web:
image: vultr-nginx
volumes:
- ./:/app
depends_on:
- php
ports:
- 80:80
Добавихме само нова услуга. Конфигурацията е почти същата, с изключение на следното.
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
The official MySQL image allows you to configure the container through simple environment variables. This can be done
with an environment
option inside the service block definition. Update the ~/docker/app/docker-compose.yml
file
to the following.
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:
Now we've defined a new service for the database. Notice the line dbdata:/var/lib/mysql
. This
mounts the path on the container /var/lib/mysql
to a persistent volume
managed by Docker, this way the database data persists after the container is removed. This
volume needs to be defined in a top-level block as you can see in the end of the file.
Преди да организираме нашата нова конфигурация, нека изтеглим примерна база данни на MySQL. В официалната документация MySQL
предоставя някои примерни бази данни. Ще използваме добре познатата световна база данни. Тази база данни предоставя списък на държави и градове. За да изтеглите тази проба, изпълнете следното в папката на нашето приложение.
curl -L http://downloads.mysql.com/docs/world.sql.gz -o world.sql.gz
gunzip world.sql.gz
Сега нека организираме нашите контейнери.
docker-compose up -d
Както може би вече сте забелязали, docker-compose up
командата стартира само контейнерите, които все още не са стартирани. Той проверява за разликите между вашия docker-compose.yml
файл и текущата конфигурация на работещи контейнери.
Още веднъж проверете дали MySQL контейнерът е стартиран.
docker ps
Сега попълнете световната база данни.
docker-compose exec -T mysql mysql -uroot -proot world < world.sql
Можете да проверите дали базата данни е попълнена, като изберете данни директно от базата данни. Първо влезте в подканата на MySQL вътре в контейнера.
docker-compose exec mysql mysql -uroot -proot world
В подканата на MySQL изпълнете следното.
select * from city limit 10;
Ще видите списък с градове. Сега излезте от подканата на MySQL.
mysql> exit
Изграждане на нашето приложение
Сега, когато всички необходими контейнери са готови и работят, можем да се съсредоточим върху нашето примерно приложение. Актуализирайте
app/index.php
файла до следното.
<?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>
Ако влезете [vultr-instance-ip]
в уеб браузър, ще видите списък с най-гъсто населените градове в света. Поздравления, разположихте напълно работещо PHP приложение с помощта на docker.
Заключение
В този урок демонстрирах стъпка по стъпка как да конфигурирате напълно работещо PHP приложение. Изградихме персонализирани изображения за PHP и Nginx и конфигурирахме docker-compose, за да организираме нашите контейнери. Въпреки че е много елементарна и проста, тази настройка отразява сценарий от реалния живот.
В това ръководство сме изградили и маркирали нашите изображения локално. За по-гъвкава настройка можете да изпратите тези изображения в регистъра на docker . Можете да натиснете към официалния регистър на докерите или дори да настроите свой собствен регистър на докерите. Във всеки случай това ще ви позволи да изградите вашите изображения на един хост и да ги използвате на друг.
За по-подробно използване на docker-compose
, трябва да се обърнете към официалната документация .
В зависимост от изискванията на вашето приложение и PHP рамката, която използвате, може да искате да добавите още разширения. Това може лесно да се направи чрез модифициране на Dockerfile
използваното за изграждане на нашето персонализирано PHP изображение. Някои разширения обаче се нуждаят от допълнителни зависимости, за да бъдат инсталирани в контейнера. Трябва да се обърнете към списъка с разширения в официалната документация на
PHP, за да прегледате основните изисквания за всяко разширение.