はじめまして。株式会社アドグローブWeb&アプリ事業部の近藤です。
みなさんは、普段、開発環境はどのように用意してますか?
私が担当するプロジェクトでは、よくDockerを使っており、本番環境をAWSで動かすことが多いので、本記事では「普段どのようにDocker開発しているか」を簡単にご紹介します。
どなたかの参考になれば幸いです。
目次
本記事で出来ること
- 開発環境と本番環境の環境差異を少なくできる
- 開発環境にS3の互換サービスを構築することでAWS側に環境を用意する必要がなくなる
全体ファイル構成
ファイルは Gitlab でも公開しています。
良かったら参考にしてください。
Gitlab:https://gitlab.com/adglobe/blog/t-kondo/sample-1
以下に全体的なディレクトリやファイル構成を示します。
一つずつファイルの中身を説明していきましょう。
. ├── docker-aws/ │ ├── nginx/ │ | ├── Dockerfile │ | └── config/ │ | └── nginx.conf │ └── php/ │ ├── Dockerfile │ └── config/ │ ├── php-fpm.conf │ ├── php.ini │ └── www.conf ├── docker-local/ │ ├── nginx/ │ | ├── Dockerfile │ | └── config/ │ | └── nginx.conf │ ├── php/ │ | ├── Dockerfile │ | └── config/ │ | ├── php-fpm.conf │ | ├── php.ini │ | └── www.conf │ ├── mysql/ │ | ├── Dockerfile │ | └── config/ │ | ├── mysql.cnf │ | └── mysqld.cnf │ └── minio/ │ ├── Dockerfile │ ├── data/ │ ├── export/ │ └── policies/ ├── src/ ├── buildspec.yml └── docker-compose.yml
各ファイル説明
docker-aws/
AWS ECS にデプロイする際に必要となるECRイメージの定義ファイルです。
ミドルウェア(Nginx, PHP)別にディレクトリを分けてDockerfileを管理してます。
docker-aws/nginx/Dockerfile
Nginxを作成するためのDockerfileです。
AWS上で稼働させるためイメージは amazonlinux:2 を利用することが多いのですが、FROM amalinux:2
と指定する方法ではデプロイの度に yum update
を走らせてしまうことになり、細かいミドルウェアのバージョンが変化してしまうため、ベースイメージ(DOCKER_REPOSITORY_URI_NGINX)を作成してそれを指定するようにしています。
ARG DOCKER_REPOSITORY_URI_NGINX FROM ${DOCKER_REPOSITORY_URI_NGINX}:latest RUN mkdir -p /code COPY ./src/public /code/public COPY ./docker-aws/nginx/config/nginx.conf /etc/nginx/nginx.conf
ベースイメージ(DOCKER_REPOSITORY_URI_NGINX)について
以下のDockerfileを作成してECRにプッシュしておき、
DOCKER_REPOSITORY_URI_NGINX
は、ECRのリポジトリURLを指定します。
FROM amazonlinux:2 RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime RUN yum -y update RUN amazon-linux-extras enable nginx1 ENV NGINX_VERSION="1.20.0" RUN yum -y install --enablerepo=amzn2extra-nginx1 \ nginx-${NGINX_VERSION} RUN yum clean all EXPOSE 80 CMD ["/usr/sbin/nginx", "-g", "daemon off;"]
docker-aws/nginx/config/nginx.conf
Nginx設定ファイルです。
下記の設定では、以下のことをしてます。
- ECSを意識してエラーログは標準出力
- php-fpmを8080ポートで起動させるので「127.0.0.1:8080」を指定
まるまるコピーするのではなく、間違いがないようにオリジナルファイルをコピーしてきて必要箇所を修正するのが良いと思います。
user nginx; worker_processes auto; worker_rlimit_nofile 50000; error_log /dev/stderr; pid /run/nginx.pid; include /usr/share/nginx/modules/*.conf; events { worker_connections 4096; use epoll; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for" $request_time'; map $http_user_agent $log_ua { ~ELB-HealthChecker 0; default 1; } access_log /dev/stdout main if=$log_ua; error_log /dev/stderr; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 60; client_header_timeout 60; client_body_timeout 60; send_timeout 60; reset_timedout_connection on; types_hash_max_size 2048; client_max_body_size 512M; server_tokens off; gzip on; gzip_vary on; gzip_disable "msie6"; gzip_proxied any; gzip_min_length 1024; gzip_comp_level 6; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; include /etc/nginx/mime.types; default_type application/octet-stream; include /etc/nginx/conf.d/*.conf; server { listen 80; server_name _; root /code/public; index index.php; include /etc/nginx/default.d/*.conf; location = /favicon.ico { empty_gif; access_log off; log_not_found off; } location / { try_files $uri $uri/ /index.php$is_args$args; location ~ \.php$ { fastcgi_pass 127.0.0.1:8080; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } } } }
docker-aws/php/Dockerfile
PHPを作成するためのDockerfileです。
AWS上で稼働させるためイメージは amazonlinux:2 を利用することが多いですが、FROM amalinux:2
と指定する方法ではデプロイの度に yum update
が走ってしまい細かいミドルウェアのバージョンが変化してしまうため、ベースイメージ(DOCKER_REPOSITORY_URI_PHP)を作成してそれを指定するようにしています。
ARG DOCKER_REPOSITORY_URI_PHP FROM ${DOCKER_REPOSITORY_URI_PHP}:latest RUN mkdir -p /code COPY ./src /code COPY ./docker-aws/php/config/php.ini /etc/php.ini COPY ./docker-aws/php/config/php-fpm.conf /etc/php-fpm.conf COPY ./docker-aws/php/config/www.conf /etc/php-fpm.d/www.conf RUN chmod 777 -R /code/storage
ベースイメージ(DOCKER_REPOSITORY_URI_PHP)について
以下のDockerfileを作成してECRにプッシュしておき、
DOCKER_REPOSITORY_URI_PHP
は、ECRのリポジトリURLを指定します。
FROM amazonlinux:2 RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime RUN yum -y update RUN amazon-linux-extras enable php8.0 ENV PHP_VERSION="8.0.13" RUN yum -y install --enablerepo=amzn2extra-php8.0 \ php-${PHP_VERSION} RUN yum -y install php-devel-${PHP_VERSION} \ php-pdo-${PHP_VERSION} \ php-fpm-${PHP_VERSION} \ php-mysqlnd-${PHP_VERSION} \ php-mbstring-${PHP_VERSION} \ php-xml-${PHP_VERSION} \ php-pear-${PHP_VERSION} RUN yum clean all EXPOSE 8080 CMD ["/usr/sbin/php-fpm", "--nodaemonize"]
docker-aws/php/config/php-fpm.conf
オリジナルファイルをコピーしてきます。
設定の修正があればしておきましょう。
docker-aws/php/config/php.ini
オリジナルファイルをコピーしてきます。
設定の修正があればしておきましょう。
docker-aws/php/config/www.conf
オリジナルファイルをコピーしてきます。
設定の修正があればしておきましょう。
docker-local/
開発環境向けのDocker定義ファイルです。
ミドルウェア(Nginx、PHP、MySQL)別にディレクトリを分けてDockerfileを管理してます。
docker-local/nginx/Dockerfile
開発環境用のNginxを作成するためのDockerfileです。
本番環境はAWSで動かすため、OS は AmazonLinux2 を指定しています。
Nginxのインストールバージョンに差異が出ないよう、バージョンを指定しています。
FROM amazonlinux:2 RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime RUN yum -y update RUN amazon-linux-extras enable nginx1 ENV NGINX_VERSION="1.20.0" RUN yum -y install --enablerepo=amzn2extra-nginx1 \ nginx-${NGINX_VERSION} RUN yum clean all WORKDIR /code EXPOSE 80 CMD ["/usr/sbin/nginx", "-g", "daemon off;"]
docker-local/nginx/config/nginx.conf
開発環境用のNginx設定ファイルです。
環境差分を無くすため、docker-aws/nginx/config/nginx.conf と同設定ですが、開発環境はdocker-compose.ymlで定義するため、phpコンテナの指定部分のみを書き換えます。
- fastcgi_pass 127.0.0.1:8080; + fastcgi_pass php:8080;
docker-local/php/Dockerfile
開発環境用のPHPを作成するためのDockerfileです。
本番環境はAWSで動かすため、OS は AmazonLinux2 を指定しています。
PHPのインストールバージョンに差異が出ないよう、バージョンを指定しています。
FROM amazonlinux:2 RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime RUN yum -y update RUN amazon-linux-extras enable php8.0 ENV PHP_VERSION="8.0.13" RUN yum -y install --enablerepo=amzn2extra-php8.0 \ php-${PHP_VERSION} RUN yum -y install php-devel-${PHP_VERSION} \ php-pdo-${PHP_VERSION} \ php-fpm-${PHP_VERSION} \ php-mysqlnd-${PHP_VERSION} \ php-mbstring-${PHP_VERSION} \ php-xml-${PHP_VERSION} \ php-pear-${PHP_VERSION} RUN yum clean all WORKDIR /code EXPOSE 9000 CMD ["/usr/sbin/php-fpm", "--nodaemonize"]
docker-local/php/config/php-fpm.conf
オリジナルファイルをコピーしてきます。
設定の修正があればしておきましょう。
docker-local/php/config/php.ini
オリジナルファイルをコピーしてきます。
設定の修正があればしておきましょう。
docker-local/php/config/www.conf
オリジナルファイルをコピーしてきます。
設定の修正があればしておきましょう。
docker-local/mysql/Dockerfile
開発環境用のDB(MySQL)を作成するためのDockerfileです。
AWSでは Aurora MySQL を利用することが多いので、MariaDBではなくMySQLをインストールします。
Aurora MySQL とのバージョン差異を最小化するために、AWS環境構築時点の Aurora MySQL バージョンを調べて同じバージョンの MySQL を指定します。
FROM mysql:5.7
docker-local/minio/Dockerfile
Amazon S3互換のオブジェクトストレージ環境を作成するためのDockerfileです。
FROM minio/minio:RELEASE.2020-11-19T23-48-16Z
古いバージョンを指定してますが、新しいバージョンだと ListObjects でエラーになるので仕方なく(なんでだろう...)。
src/
PHPフレームワークをここに入れています。
弊社ではLaravelを利用することが多いです。
buildspec.yml
CodePipelineで利用するCodeBuildの設定ファイルです。
ECS を利用するため、ECRへDockerイメージをプッシュするところまで行います。
version: 0.2 env: variables: DOCKER_BUILDKIT: "1" phases: install: runtime-versions: php: 8.0 pre_build: commands: - aws --version - echo Logging in to Amazon ECR... - aws ecr get-login-password | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com - REPOSITORY_URI_NGINX=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${IMAGE_NAME_NGINX} - REPOSITORY_URI_PHP=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${IMAGE_NAME_PHP} - IMAGE_TAG=${CODEBUILD_RESOLVED_SOURCE_VERSION} build: commands: - echo Build started on `date` # PHP Build - cd src/ - composer install - cd .. # Nginx container Build - echo Building the Nginx Docker image... - docker build -t ${REPOSITORY_URI_NGINX}:latest -f ./docker-aws/nginx/Dockerfile --build-arg DOCKER_REPOSITORY_URI_NGINX=${DOCKER_REPOSITORY_URI_NGINX} . - docker tag ${REPOSITORY_URI_NGINX}:latest ${REPOSITORY_URI_NGINX}:${IMAGE_TAG} # PHP container Build - echo Building the PHP Docker image... - docker build -t ${REPOSITORY_URI_PHP}:latest -f ./docker-aws/php/Dockerfile --build-arg DOCKER_REPOSITORY_URI_PHP=${DOCKER_REPOSITORY_URI_PHP} . - docker tag ${REPOSITORY_URI_PHP}:latest ${REPOSITORY_URI_PHP}:${IMAGE_TAG} - echo Build completed on `date` post_build: commands: - echo Pushing the Docker images... # DB migration - cd src/ - php artisan migrate --force - cd .. # Nginx container Push - docker push ${REPOSITORY_URI_NGINX}:${IMAGE_TAG} - docker push ${REPOSITORY_URI_NGINX}:latest # PHP container Push - docker push ${REPOSITORY_URI_PHP}:${IMAGE_TAG} - docker push ${REPOSITORY_URI_PHP}:latest - echo Writing image definitions file... - echo "[{\"name\":\"${CONTAINER_NAME_NGINX}\",\"imageUri\":\"${REPOSITORY_URI_NGINX}:${IMAGE_TAG}\"},{\"name\":\"${CONTAINER_NAME_PHP}\",\"imageUri\":\"${REPOSITORY_URI_PHP}:${IMAGE_TAG}\"}]" - echo "[{\"name\":\"${CONTAINER_NAME_NGINX}\",\"imageUri\":\"${REPOSITORY_URI_NGINX}:${IMAGE_TAG}\"},{\"name\":\"${CONTAINER_NAME_PHP}\",\"imageUri\":\"${REPOSITORY_URI_PHP}:${IMAGE_TAG}\"}]" > imagedefinitions.json artifacts: files: - imagedefinitions.json
docker-aws/nginx/Dockerfile、docker-aws/php/Dockerfile の設定で登場する環境変数「DOCKER_REPOSITORY_URI_NGINX」「DOCKER_REPOSITORY_URI_PHP」を渡してます。
docker-compose.yml
version: '3' services: nginx: container_name: ${COMPOSE_PROJECT_NAME}-nginx build: context: ./docker-local/nginx/ ports: - "${WEB_PORT-80}:80" volumes: - ./src/:/code - ./docker-local/nginx/config/nginx.conf:/etc/nginx/nginx.conf depends_on: - php networks: - common php: container_name: ${COMPOSE_PROJECT_NAME}-php build: context: ./docker-local/php/ environment: APP_ENV: local DB_HOST: mysql DB_DATABASE: ${DB_DATABASE} DB_USERNAME: ${DB_USERNAME} DB_PASSWORD: ${DB_PASSWORD} DB_PORT: 3306 AWS_ACCESS_KEY_ID: ${MINIO_ACCESS_KEY} AWS_SECRET_ACCESS_KEY: ${MINIO_SECRET_KEY} volumes: - ./src/:/code - ./docker-local/php/config/php.ini:/etc/php.ini - ./docker-local/php/config/php-fpm.conf:/etc/php-fpm.conf - ./docker-local/php/config/www.conf:/etc/php-fpm.d/www.conf networks: - common mysql: platform: linux/x86_64 container_name: ${COMPOSE_PROJECT_NAME}-mysql build: context: ./docker-local/mysql/ hostname: localhost environment: HOSTNAME: localhost MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: ${DB_DATABASE} MYSQL_USER: ${DB_USERNAME} MYSQL_PASSWORD: ${DB_PASSWORD} TZ: Asia/Tokyo command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_bin ports: - "${DB_PORT-3306}:3306" volumes: - ./docker-local/mysql/config/mysql.cnf:/etc/mysql/conf.d/mysql.cnf - ./docker-local/mysql/config/mysqld.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf - dbstorage:/var/lib/mysql networks: - common minio: container_name: ${COMPOSE_PROJECT_NAME}-minio build: context: ./docker-local/minio/ ports: - "${MINIO_WEB_PORT-9000}:9000" volumes: - ./docker-local/minio/data:/data - ./docker-local/minio/export:/export - ./docker-local/minio/policies:/policies environment: MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY} MINIO_SECRET_KEY: ${MINIO_SECRET_KEY} TZ: Asia/Tokyo command: -c " mkdir -p /data/.minio.sys/buckets; cp -r /policies/* /data/.minio.sys/; cp -r /export/* /data/; /usr/bin/minio server /data;" entrypoint: sh networks: - common volumes: dbstorage: driver: local networks: common: driver: bridge