понедельник, 5 декабря 2016 г.

Запуск PHP приложения на Docker контейнерах (PHP-FPM, Nginx, PostgreSQL) / Хабрахабр

Back-end разработчик
6,4
рейтинг
вчера в 17:49

Администрирование → Запуск PHP приложения на Docker контейнерах (PHP-FPM, Nginx, PostgreSQL) из песочницы

За последний год программное обеспечение для автоматизации развертывания в среде виртуализации на уровне операционной системы набирает большие обороты. Эта статья послужит новичкам в этой сфере примером, как нужно упаковывать свое приложение в Docker контейнеры.

В классическом виде, PHP приложение представляет из себя следующие составляющие:

  1. Веб-сервер
  2. СУБД
  3. PHP приложение

В нашем примере мы будем использовать Nginx, PostgreSQL и PHP-FPM.

1. Установка Docker


Для начала работы, нам потребуется Docker. Скачать его можно на официальном сайте Docker.

2. Создание образов


Docker создает образы на основе DockerFile файлов, в котором описывается функционал. Мы создадим 3 образа для наших составляющих.

DockerFileNginx


FROM nginx:mainline-alpine    RUN set -ex \   && addgroup -g 82 -S www-data \   && adduser -u 82 -D -S -G www-data www-data \      && mkdir -p /etc/pki/nginx/ \      && apk update \      && apk --no-cache add --update openssl \      && openssl dhparam -out /etc/pki/nginx/dhparams.pem 4096 \      && sed -i -e 's/user\s*nginx;/user  www-data www-data;/g' /etc/nginx/nginx.conf \      && sed -i -e 's/worker_processes\s*1;/worker_processes  auto;/g' /etc/nginx/nginx.conf \      && rm -rf /var/cache/apk/*    COPY config/website.conf /etc/nginx/conf.d/website.conf  

В данном DockerFile мы создаем пользователя www-data с группой 82 и устанавливаем Nginx. Последняя строка COPY предполагает, что у вас конфигурация приложения лежит в папке config/website.conf. Она скопируется в /etc/nginx/conf.d/website.conf.

DockerFilePostgresql


FROM postgres:9.5.2    RUN localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8  ENV LANG en_US.utf8

В этом образе, мы будем отталкиваться от образа postgres:9.5.2 и выполним команду для определения локали и языка.

DockerFile


FROM alpine:edge    # Timezone  ENV TIMEZONE Europe/Moscow  ENV PHP_MEMORY_LIMIT 1024M  ENV MAX_UPLOAD 128M  ENV PHP_MAX_FILE_UPLOAD 128  ENV PHP_MAX_POST 128M</blockquote>    RUN set -ex \  	&& addgroup -g 82 -S www-data \  	&& adduser -u 82 -D -S -G www-data www-data \  	&& echo "@testing http://dl-4.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories \      && apk update \      && apk upgrade \      && apk add --update tzdata \  	&& cp /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \  	&& echo "${TIMEZONE}" > /etc/timezone \      && apk --update add --no-cache php7-fpm@testing php7-mcrypt@testing php7-openssl@testing php7-json@testing php7-mysqli@testing php7-session@testing php7-gd@testing php7-xmlreader@testing php7-xmlrpc@testing \      php7-zip@testing php7-iconv@testing php7-curl@testing php7-zlib@testing php7@testing php7-ctype@testing php7-pgsql@testing php7-pdo_pgsql@testing bash rsync \      && sed -i -e "s/;daemonize\s*=\s*yes/daemonize = no/g" /etc/php7/php-fpm.conf \      && sed -i -e "s/listen\s*=\s*127.0.0.1:9000/listen = [::]:9000/g" /etc/php7/php-fpm.d/www.conf \      && sed -i -e "s/;chdir\s*=\s*\/var\/www/chdir = \/usr\/src\/app/g" /etc/php7/php-fpm.d/www.conf \      && sed -i -e "s/user\s*=\s*nobody/user = www-data/g" /etc/php7/php-fpm.d/www.conf \      && sed -i -e "s/group\s*=\s*nobody/group = www-data/g" /etc/php7/php-fpm.d/www.conf \      && sed -i -e "s/;clear_env\s*=\s*no/clear_env = no/g" /etc/php7/php-fpm.d/www.conf \      && sed -i -e "s/;catch_workers_output\s*=\s*yes/catch_workers_output = yes/g" /etc/php7/php-fpm.d/www.conf \      && sed -i "s|;date.timezone =.*|date.timezone = ${TIMEZONE}|" /etc/php7/php.ini \      && sed -i "s|memory_limit =.*|memory_limit = ${PHP_MEMORY_LIMIT}|" /etc/php7/php.ini \      && sed -i "s|upload_max_filesize =.*|upload_max_filesize = ${MAX_UPLOAD}|" /etc/php7/php.ini \      && sed -i "s|max_file_uploads =.*|max_file_uploads = ${PHP_MAX_FILE_UPLOAD}|" /etc/php7/php.ini \      && sed -i "s|post_max_size =.*|post_max_size = ${PHP_MAX_POST}|" /etc/php7/php.ini \      && sed -i "s/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/" /etc/php7/php.ini \      && apk del tzdata \      && rm -rf /var/cache/apk/*    COPY . /usr/src/app    RUN chown -R www-data:www-data /usr/src/app    EXPOSE 9000    CMD ["php-fpm7"]

Этот образ послужит нам основным образом для нашего приложения. Сначала мы устанавливаем все необходимое для PHP и PHP-FPM. Далее, мы копируем текущую папку приложения в /usr/src/app, где будет распологаться наше приложение. В самом конце мы запускаем PHP-FPM.

Создание образов на основе DockerFile'ов


И так, у нас есть есть DockerFile'ы, на основе которых мы должны создать образы. Образы создаются очень просто. Достаточно выполнить следующие команды:

docker build -t myusername/myproject-nginx:latest -f DockerfileNginx .

docker build -t myusername/myproject-postgresql:latest -f DockerfilePostgreSql .

docker build -t myusername/myproject:latest .

В дальнейшем советую добавить к этим командам --no-cache, чтобы каждый раз не компилировать составляющие.

Мы создаем образы, прикрепляем их к нашему аккаунту на Docker Hub. Теперь, нам нужно отправить наши образы на репозиторий в Docker Hub. Выполняем следующие команды:

docker push myusername/myproject-nginx:latest

docker push myusername/myproject-postgresql:latest

docker push myusername/myproject:latest

Запуск образов на сервере


Мы почти у цели! Нам осталось загрузить образы из репозитория и запустить их. Загружаем их с помощью следующих команд:

docker pull myusername/myproject-nginx:latest

docker pull myusername/myproject-postgresql

docker pull myusername/myproject

Осталось их запустить. Делается это так же просто.

docker run —name myproject-nginx -d -p 80:80 myusername/myproject-nginx:latest

docker run —name myproject-postgresql9.5.2 -d -p 5432:5432 myusername/myproject-postgresql9.5.2:latest

docker run —name myproject -d -p 9000:9000 myusername/myproject:latest  

Вуаля! Наше приложение запущено на Docker контейнерах. И тем не менее, всем читателям-новичкам я бы обязательно ознакомиться с документацией Docker.

Всем желаю успехов в освоении новых технологий!
Тигран Мурадян @EmotionTigran
карма
2,0
рейтинг 6,4
Back-end разработчик
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Администрирование

Комментарии (12)

  • +2
    Кстати, если вы работаете над несколькими взаимодействующими веб-приложениями, то для связки нужно будет использовать docker-compose, дам мой пример:
    Заголовок спойлера
    version: "2"    networks:      lan_0:          driver: bridge          ipam:              driver: default              config:                  - subnet: 172.19.0.0/24                    gateway: 172.19.0.21    services:      nginx:          build: ./nginx/          ports:              - 80:80              - 443:443          links:              - php          volumes:              - ./code:/var/www/          networks:              lan_0:                  ipv4_address: 172.19.0.22      php:          build: ./php/          expose:              - 9000          volumes:              - ./code/:/var/www/          extra_hosts:              - "website.local:172.19.0.22"              - "api.local:172.19.0.22"          networks:              lan_0:                  ipv4_address: 172.19.0.23      mysql:          build: ./mysql/          environment:              MYSQL_ROOT_PASSWORD: root              MYSQL_DATABASE: dev          ports:              - 3306:3306          volumes:              - ./mysql/sql:/docker-entrypoint-initdb.d              - ./mysql/data:/var/lib/mysql          networks:              lan_0:                  ipv4_address: 172.19.0.12  

    то есть, путем прокладывания сети.
    • 0
      в docker-compose version 1 все гораздо проще.
      • 0
        Указывать явные IP необязательно, docker-compose автоматически перелинкует контейнеры и они по умолчанию будут доступны по имени своего service. В примере выше, вероятно, было важно иметь фиксированные IP.
    • 0
      Я бы вообще ничего без docker-compose не запускал, иначе потом черт ногу сломит с этими контейнерами, а compose делает имена вида folder_service_n, делает сам отдельную сетку с таким же названием папки.

      Кстати, а зачем вообще указывать extra_hosts и IP адреса? Docker же позволяет внутри одной сети работать просто по имени сервиса, да и порты все наружу открывать не нужно, достаточно только для nginx.
      • +1
        Docker-compose хороший инструмент и конечно же его стоит использовать. Но все же, я бы исключил его для новичков, которые только-только начинают ознакамливаться с Docker'ом.
  • 0
    Можете мне пояснить, как человеку незнакомому с Docker: если ли смысл использовать описанный подход вместо связки Vagrant + VirtualBox?
    • 0
      вагрант — очень тугой инструмент, докер же быстрее, да и удобнее, как по мне.
    • 0
      Если все устраивает, то переходить резко на докер я бы не стал. Для нового приложения имеет смысл попробовать.
    • 0
      Все от задач зависит. Лично я использую докер в нескольких виртуалках, развернутых варгантом (к слову, вагрант не показался мне удачным решением для разворачивания и уж тем более управления большим количеством виртуалок). Опять же, если требуется запустить зоопарк сервисов на одной машине, то докер отличное решение. Если же нужно давать доступ к машине 3-м лицам, то однозначно виртуалки.
    • 0
      Если ваша связка Vagrant + Virtualbox работает стабильно, и у вас нет необходимости периодически добавлять новые сервисы в проект, то данную связку вполне удобно использовать, особенно если у вас уже все настроено и отлажено, включая процессы.

      Но если вы захотите сделать апгрейд вашей системы, то наверно уже стоит подумать об уходе от зависимости от Vagrant.

      Я как раз имел такой опыт перехода с Vagrant на Docker. И при этом столкнулся с рядом трудностей. Например, Docker из коробки не предлагает никакой автоматизации. Есть конечно docker-compose, но его возможности по сравнению с Vagrant весьма скудные (YAML все-таки не сравнить с полноценным ЯП). В итоге пришлось разрабатывать свое собственное решение.

      Если вы все же захотите попробовать Docker без отказа от Vagrant, то последний предоставляет такую возможность, но разобраться в настройке не так то просто. Мне очень помогло в свое время вот это описание процесса настройки Vagrant + Docker.
  • +2
    Куча sed'ов выглядит ужасно. Я бы просто создал конфиг-файл и переписал бы им дефолтный файл конфига
    • 0
      Куча sed'ов выглядит ужасно.
      Альтернативы ни чем не лучше, везде будет тот же самый PCRE (в лучшем случае)
      Я бы просто создал конфиг-файл и переписал бы им дефолтный файл конфига
      Простые решения увы не всегда подходят, иногда надо сохранить имеющийся конфиг. А со временем приходит понимание, что sed вовсе не ужасен, а совсем даже наоборот

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.



Original Page: https://habrahabr.ru/post/316802/



Sent from my iPad

Комментариев нет:

Отправить комментарий