Docker(도커)로 APM ( Apache + PHP + MySQL ) 환경을 구축해보겠습니다.

도커가 설치되어 있지 않다면 도커를 먼저 설치해주세요.
( https://docs.docker.com/get-docker/  )

실행

Git 저장소 Clone

git clone https://github.com/dantory/-Docker-APM.git

스크립트 실행

cd docker
sh ./scripts/create.sh

/etc/hosts 파일에 테스트 도메인 추가
( 테스트를 위해 임의로 설정된 도메인이므로 추후 도메인명 수정 필요. )

echo "127.0.0.1 test.mydomain.com" | sudo tee -a /etc/hosts

구조 살펴보기

디렉토리 구조

➜  docker-apm git:(master) tree
├── README.md
├── app
│   └── test.mydomain.com
│       ├── error.php
│       └── index.php
├── database
├── docker
│   ├── apache
│   │   ├── Dockerfile
│   │   ├── httpd-vhosts.conf
│   │   └── httpd.conf
│   ├── docker-compose.yml
│   ├── mysql
│   │   └── Dockerfile
│   ├── php
│   │   ├── Dockerfile
│   │   └── www.conf
│   └── scripts
│       ├── create.sh
│       └── destroy.sh
└── logs

– app: 도메인 별로 PHP 소스 ( vhost 설정에 따라 변경 가능. )
– database: 데이터베이스 파일 ( docker 실행 시 mysql container 의 db data 가 저장됨 )
– docker: 도커 build 및 설정 파일
– logs: 도커 컨테이너별 로그 저장 디렉토리

docker-compose.yml 파일

파일위치: docker/docker-compose.yml

서비스별로 도커 이미지를 생성해서 관리해도 되지만 Apache, PHP, MySQL은 유기적으로 돌아가는 부분이므로
여러 컨테이너 서비스들을 묶어서 관리함에 있어 용이하도록 docker-compose 를 활용하였습니다.

docker-compse.yml 파일 내용은 아래와 같습니다.

version: '3'

services:
    apache_img:
        container_name: ${PROJECT_NAME}_apache
        build:
            context: ./apache
            args:
                - WEB_USER=${WEB_USER}
                - WEB_GROUP=${WEB_GROUP}
                - APACHE_ROOT_DIR=${APACHE_ROOT_DIR}
        volumes:
            - ../${PHP_APP_DIR}:${PHP_APP_DIR}
            - ../logs/apache:${APACHE_ROOT_DIR}/logs
        ports:
            - ${APACHE_EXPOSED_PORT}:80
        networks:
            apm_net:
                ipv4_address: ${APACHE_IP}
        environment:
            - APACHE_EXPOSED_PORT=${APACHE_EXPOSED_PORT}
            - APACHE_ROOT_DIR=${APACHE_ROOT_DIR}
            - PHP_IP=${PHP_IP}
            - PHP_APP_DIR=${PHP_APP_DIR}
            - PHP_EXPOSED_PORT=${PHP_EXPOSED_PORT}
            - WEB_USER=${WEB_USER}
            - WEB_GROUP=${WEB_GROUP}
    php_img:
        container_name: ${PROJECT_NAME}_php
        build:
            context: ./php
            args:
                - WEB_USER=${WEB_USER}
                - WEB_GROUP=${WEB_GROUP}
                - PHP_ROOT_DIR=${PHP_ROOT_DIR}
        working_dir: ${PHP_APP_DIR}
        volumes:
            - ../${PHP_APP_DIR}:${PHP_APP_DIR}
            - ../logs/php:${PHP_ROOT_DIR}/logs
        networks:
            apm_net:
                ipv4_address: ${PHP_IP}
        environment:
            - PHP_ROOT_DIR=${PHP_ROOT_DIR}
            - APACHE_IP=${APACHE_IP}
            - APACHE_EXPOSED_PORT=${APACHE_EXPOSED_PORT}
            - WEB_USER=${WEB_USER}
            - WEB_GROUP=${WEB_GROUP}
            - MYSQL_IP=${MYSQL_IP}
            - MYSQL_ROOT_USER=${MYSQL_ROOT_USER}
            - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
    mysql_img:
        container_name: ${PROJECT_NAME}_mysql
        build:
            context: ./mysql
            args:
                - MYSQL_CONTAINER_USER=${MYSQL_CONTAINER_USER}
                - MYSQL_CONTAINER_GROUP=${MYSQL_CONTAINER_GROUP}
        volumes:
            - ../logs/mysql:${MYSQL_LOG_DIR}
            - ../database:${MYSQL_DATA_DIR}
        networks:
            apm_net:
                ipv4_address: ${MYSQL_IP}
        environment:
            - MYSQL_CONTAINER_USER=${MYSQL_CONTAINER_USER}
            - MYSQL_CONTAINER_GROUP=${MYSQL_CONTAINER_GROUP}
            - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}

networks:
    apm_net:
        driver: bridge
        ipam:
            driver: default
            config:
                - subnet: ${NETWORK_SUBNET}

현재 설정된 docker-compose 옵션은 크게 version, services, networks 로 나눠집니다.

각 항목들을 하나씩 간략하게 살펴보겠습니다.

version

docker-compose 의 version 을 설정합니다.
버전 별로 옵션을 설정하는 방식이나 지원하는 기능이 달라지기때문에 최신버전인 3 버전을 사용하였습니다.

services

services 의 설정된 apache_img, php_img, mysql_img 로 도커 이미지가 만들어지게 됩니다.
실제 만들어진 이미지에는 디렉토리명이 prefix 로 붙게됩니다. 
( docker 디렉토리에서 스크립트를 실행해서 이미지가 만들어졌으므로 docker_ 가 prefix 로 추가됨 )

– 도커 생성시 이미지 생성 예시)

➜  docker git:(master) docker images    
REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
docker_mysql_img                     latest              bd7c58353f05        About an hour ago   448MB
docker_php_img                       latest              6cc7671397bb        About an hour ago   344MB
docker_apache_img                    latest              2a416fc23e5e        About an hour ago   186MB

그리고 이미지를 컨테이너화시켰을때의 컨테이너명은 container_name 항목에 지정해주었으며,
환경설정값 ( .env 파일에 정의된 값) PROJECT_NAME 에 _apache or _php or _mysql 등으로 지정.

– 도커 실행 시 컨테이너 생성 예시)

➜  docker git:(master) docker-compose ps
     Name                   Command              State          Ports       
----------------------------------------------------------------------------
DemoAPM_apache   httpd-foreground                Up      0.0.0.0:80->80/tcp 
DemoAPM_mysql    docker-entrypoint.sh mysqld     Up      3306/tcp, 33060/tcp
DemoAPM_php      docker-php-entrypoint php-fpm   Up      9000/tcp 

그리고 이후로 서비스별로 설정된 옵션을 간략하게 설명드리면,

– build: 도커 이미지를 빌드하기 위한 옵션 파일의 위치(context)를 지정하고 필요한 파라미터(args) 를 설정.
– volumes: 도커 컨테이너 내부에 파일 or 디렉토리를 호스트에 저장할 대상
( 도커 컨테이너에 생성되는 설정 파일이나 로그파일을 호스트에서 관리할 수 있도록 하기 위함. )
– ports: 호스트에서 도커 컨테이너의 특정 포트로 접근할 수 있게 해주는 설정.
– networks: 컨테이너별 네트워크 설정.
– environment: 컨테이너에서 사용할 환경 변수들 설정

networks

컨테이너간의 통신을 위해 네트워크를 만들어주고 할당해주기 위해 설정합니다.
( 별도의 설정을 하지 않아도 임의적인 네트워크를 만들어주지만 추후 관리의 용이성을 위해 별도로 설정하는게 좋습니다. )

도커 실행 시 네트워크 생성 예시)

➜  docker git:(master) docker network ls   
NETWORK ID          NAME                DRIVER              SCOPE
5b919fb88f90        docker_apm_net      bridge              local

docker-compose 의 옵션 및 사용법에 대한 자세한 내용은 공식 문서를 참조해주세요.
https://docs.docker.com/compose/

설정 입맛대로 변경해보기

# 테스트 도메인(test.mydomain.com) 변경하기

현재 Apache 설정은 test.mydomain.com 로만 접속되도록 설정되어있는데요,
다른 도메인으로 변경하고 싶다면 vhost 설정을 변경해야합니다.

우선 vhost 설정 파일은 docker/apache/httpd-vhosts.conf 입니다.
해당 파일을 에디터로 열어보시면 아래와 같이 되어있구요.

<VirtualHost *:80>
    ServerName localhost
    DocumentRoot ${APACHE_ROOT_DIR}/htdocs

    <Directory ${APACHE_ROOT_DIR}/htdocs>
        Require all denied
    </Directory>

    ErrorLog ${APACHE_ROOT_DIR}/logs/localhost.error.log
    CustomLog ${APACHE_ROOT_DIR}/logs/localhost.access.log common
</VirtualHost>

<VirtualHost *:80>
    ServerAdmin webmaster@mydomain.com
    DocumentRoot ${PHP_APP_DIR}/test.mydomain.com
    ServerName test.mydomain.com

    ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://${PHP_IP}:${PHP_EXPOSED_PORT}${PHP_APP_DIR}/test.mydomain.com/$1

    <Directory ${PHP_APP_DIR}/test.mydomain.com>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_ROOT_DIR}/logs/test.mydomain.com.error.log
    CustomLog ${APACHE_ROOT_DIR}/logs/test.mydomain.com.access.log common
</VirtualHost>

보시면 2개의 VirtualHost 설정이 있는데요, 처음 설정은 localhost 접근을 막기위한 설정이니 그대로 놔두시고
두번째 설정에서 test.mydomain.com 부분을 원하는 도메인으로 설정해주세요.

그리고 /etc/hosts 파일에 설정된 test.mydomain.com 을 변경해주셔야하는데요.
/etc/hosts 파일을 루트권한으로 열어서 수정해주세요. => ex) sudo vi /etc/hosts
( 만약 /etc/hosts 파일에 도메인 추가를 안하셨던 분은 아래처럼 새로 추가해주세요. )
ex) 127.0.0.1 www.changesite.com

# PHP 버전 변경하기

만약 PHP 버전을 5에서 7로 변경하고 싶으시다면 아래와 같이 해주세요.

1. docker/php/Dockerfile 을 에디터로 열어주세요.
2. FROM php:5.6-fpm 를 FROM php:7-fpm 로 변경해주세요.
7버전중에 특정 버전을 선택하시려면 아래 링크에 나와있는 이미지들중에 원하는 php-fpm 이미지를 선택해서 사용해주세요.
github.com/docker-library/docs/blob/master/php/README.md#supported-tags-and-respective-dockerfile-links

# MySQL 호스트에서 접속하기 ( DB 포트 열기 )

현재 MySQL 은 컨테이너에서만 접근이 가능합니다.

만약 호스트에서 sql tool = ex) mysql workbench 를 활용해서 접속하고 싶으신경우
MySQL 접속포트(3306)을 호스트에서 접근가능하도록 설정해주셔야 합니다.

1. docker-compose.yml 파일을 에디터로 열어주세요.
2. mysql_img 하위 항목으로 아래처럼 ports 설정을 추가해주세요.

... 생략 ...

	mysql_img:
        container_name: ${PROJECT_NAME}_mysql
        build:
            context: ./mysql
            args:
                - MYSQL_CONTAINER_USER=${MYSQL_CONTAINER_USER}
                - MYSQL_CONTAINER_GROUP=${MYSQL_CONTAINER_GROUP}
        volumes:
            - ../logs/mysql:${MYSQL_LOG_DIR}
            - ../database:${MYSQL_DATA_DIR}
        ports:
            - 3306:3306 # mysql 포트오픈 설정 추가
        networks:
            apm_net:
                ipv4_address: ${MYSQL_IP}
        environment:
            - MYSQL_CONTAINER_USER=${MYSQL_CONTAINER_USER}
            - MYSQL_CONTAINER_GROUP=${MYSQL_CONTAINER_GROUP}
            - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
            	

... 생략 ...

그리고 root 계정으로 접속하시면 됩니다.

– MySQL 접속정보 
Hostname: localhost
Username: root
Password: .env 파일에 설정되어있는 MYSQL_ROOT_PASSWORD ( 기본은 root )

감사합니다.