Docker compose로 PHP(phalcon) + Nginx + Mysql 올리기 1부

Docker

(Update : 2021-06-14)

Language :

안녕하세요 Lovefield입니다.

최근 Docker를 사용하게 되면서 블로그도 Docker기반으로 변경하게 되었습니다. 이 블로그는 Phalcon을 기반으로 만들었는데요. Phalcon이 생각보다 까다로운 프레임워크였습니다. Phalcon을 Docker에 올리기 위해 여러 시행착오를 겪고 나서야 겨우 성공할 수 있었죠. 이번 글은 Docker 환경에서 Phalcon을 활용하는 방법에 대해 이야기해보려 합니다.

먼저 디렉토리 구조입니다, 저는 docker-compose를 사용할 때 관리 측면을 고려하여 컨테이너당 하나의 폴더를 할당하고 있습니다.

- mysql
    -data
- php
    -asset
- nginx
    -asset
    -log
- phalcon
docker-compose.yml

“mysql/data” 폴더는 디비 데이터를 저장하기 위한 공간입니다, 컨테이너 동작 유무와 별도로 데이터를 온전히 보관하기 위해 사용합니다. “php” 폴더의 asset폴더는 ini파일들이 생성될 장소죠. nginx 폴더의 asset 또한 .conf가 생성될 예정입니다.“phalcon”폴더를 따로 만드는 이유는 실제 구동 파일과 설정 파일을 구분하기 위해서입니다.

이제 docker-compose.yml파일을 작성합니다.

version: "3"
services:
    mysql:
    php:
    nginx:

최신버전을 사용하기 위해 “version”에 “3”을 씁니다. 총 3개의 컨테이너를 사용할 예정이니 “services” 안에 “mysql”, “php”, “nginx”를 작성해줍니다.

“mysql” 컨테이너 먼저 설정해 볼까요?

```
mysql:
   container_name: mysql
   image: mysql:8.0.22
   environment:
       MYSQL_DATABASE: app
       MYSQL_USER: user
       MYSQL_PASSWORD: user_pw
       MYSQL_ROOT_PASSWORD: root_pw
   command: ["mysqld", "--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"]
   volumes:
       - ./mysql/data:/var/lib/mysql:rw
   ports:
       - "3306:3306"
   restart: always
   logging:
       options:
           max-size: "1m"
           max-file: "3"
```

Mysql 8을 사용하기 위해 “image” 항목에 “mysql:8.0.22”를 입력합니다. Docker image hub에 있는 리스트에서 “mysql:8.0.22”를 가져와 사용한다는 의미죠.
“environment” 항목은 컨테이너 내에서 사용할 인자를 설정해줍니다.
“MYSQL_DATABASE”로 디비 이름을.
“MYSQL_USER”로 유저 이름을.
“MYSQL_PASSWORD”로 유저 비밀번호를.
“MYSQL_ROOT_PASSWORD”로 루트 계정 비밀번호를 설정합니다.

“command” 항목은 컨테이너가 실행되고 나서 실행할 명령어입니다. Mysql 8은 기본적으로 characterset을 utf8로 설정되어 있지만, 혹시나 모를 사태에 대비해서 관련 명령어를 넣어줍니다.
“volumes” 항목은 현제 디렉토리와 컨테이너 내의 경로를 매칭시켜줄 리스트입니다. Mysql에 들어가는 모든 데이터를 관련 폴더에 두기 위해 “./mysql/data:/var/lib/mysql:rw”를 적어줍니다. 끝에 “:rw”는 읽기와 쓰기의 권한을 부여하는 옵션입니다.
“ports” 항목은 외부포트와 컨테이너 내부 포트를 매칭시켜줍니다.
“restart” 항목은 컨테이너에 문제가 생겨 중지되었을 때 재시작 여부 옵션입니다.
“logging” 항목은 말그대로 log를 기록하기 위함인데, 이번에는 파일 하나당 최대 1mb 기록을 저장하고 최대 3개로 제한했습니다.

다음으로 “php” 컨테이너를 설정해 봅시다.

php:
   container_name: php
   build:
       context: ./php
       dockerfile: dockerfile
       args:
           - WITH_XDEBUG=true
   working_dir: /var/www/html
   volumes:
       - ./php/asset/timezone.ini:/usr/local/etc/php/conf.d/timezone.ini
       - ./php/asset/file.ini:/usr/local/etc/php/conf.d/file.ini
       - ./phalcon:/var/www/html:rw
   command: bash -c "php-fpm"
   restart: always
   logging:
       options:
           max-size: "1m"
           max-file: "3"

“php” 컨테이너는 이미지를 바로 사용하기 힘듭니다. 추가 설정을 위해 dockerfile을 사용할 예정이니 “image” 항목 대신 “build” 항목으로 dockerfile을 지정합니다. “args”는 dockerfile을 실행할때 사용할 인자입니다. php를 디버그하기 위해서 Xdebug를 설치해야겠죠? 그렇지만 실서버에서는 무거운 Xdebug를 실행할 이유가 없습니다. Xdebug 설치 유무에 대한 인자를 지정해둡시다.

“php” 폴더에 컨테이너에서 사용할 dockerfile을 작성합니다.

# php7.4-fpm 이미지 사용
FROM php:7.4-fpm

# 기본적인 라이브러리 설치
RUN apt-get update && apt-get install -y \
       libfreetype6-dev \
       libpng-dev \
       zlib1g-dev \
       g++ \
       libicu-dev \
       libmcrypt4 \
       libzip-dev \
   && docker-php-ext-install pdo_mysql \
   && docker-php-ext-install mysqli \
   && docker-php-ext-install zip

# composer 설치
RUN curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# xdebug 설치 유무 인자
ARG WITH_XDEBUG=false

# xdebug 설치
RUN set -eux; \
   if [ $WITH_XDEBUG = "true" ] ; then \
       pecl install xdebug; \
       docker-php-ext-enable xdebug; \
       echo "error_reporting = E_ALL" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
       echo "display_startup_errors = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
       echo "display_errors = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
       echo "xdebug.remote_enable=1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
       echo "xdebug.idekey=PHPSTORM" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
       echo "xdebug.remote_host=host.docker.internal" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
   fi ;

# phalcon 버전 설정
ARG PSR_VERSION=1.0.0
ARG PHALCON_VERSION=4.0.5
ARG PHALCON_EXT_PATH=php7/64bits

RUN set -xe && \
   # PSR 설치
   curl -LO https://github.com/jbboehr/php-psr/archive/v${PSR_VERSION}.tar.gz && \
   tar xzf ${PWD}/v${PSR_VERSION}.tar.gz && \
   # Phalcon 설치
   curl -LO https://github.com/phalcon/cphalcon/archive/v${PHALCON_VERSION}.tar.gz && \
   tar xzf ${PWD}/v${PHALCON_VERSION}.tar.gz && \
   docker-php-ext-install -j $(getconf _NPROCESSORS_ONLN) \
       ${PWD}/php-psr-${PSR_VERSION} \
       ${PWD}/cphalcon-${PHALCON_VERSION}/build/${PHALCON_EXT_PATH} \
   && \
   # 설치하면서 사용했던 임시 파일 삭제
   rm -r \
       ${PWD}/v${PSR_VERSION}.tar.gz \
       ${PWD}/php-psr-${PSR_VERSION} \
       ${PWD}/v${PHALCON_VERSION}.tar.gz \
       ${PWD}/cphalcon-${PHALCON_VERSION} \
   && \
   php -m

다음으로 “volumes”항목에 연결했던 php설정파일인 ini를 작성합니다. “php/asset” 폴더에 각각 timezone.ini 과 file.ini를 작성해야 합니다.

; timezone.ini
date.timezone=Asia/Seoul

; file.ini
upload_max_filesize=10M
post_max_size=10M

php상의 timezone을 한국 시간인 “Asia/Seoul”로 변경하고 업로드파일 최대 용량을 10MB로 설정했습니다.

마지막으로 “nginx” 컨테이너를 보도록 할까요?

nginx:
   container_name: nginx
   image: nginx:1.17.8
   command: ["nginx", "-g", "daemon off;"]
   working_dir: /var/www/html
   depends_on:
       - php
       - mysql
   volumes:
       - ./nginx/asset/:/etc/nginx/conf.d/
       - ./nginx/log:/var/log/nginx/:rw
       - ./phalcon:/var/www/html:rw
   ports:
       - "80:80"
   links:
       - php
   restart: always
   logging:
       options:
           max-size: "1m"
           max-file: "3"

“depends_on”을 이용해 “php”컨테이너와 “mysql”컨테이너가 실행된 이후 “nginx”컨테이너가 실행되도록 설정합니다.
“links”를 통해서 “php” 컨테이너와 연결합니다.
로그를 기록하기 위해서 “volumes”에 “./nginx/log:/var/log/nginx/:rw”폴더를 사용합니다.실제 앱이 구동되는 파일들은 “./phalcon:/var/www/html:rw” 폴더를, nginx를 설정하는 파일은 “./nginx/asset/:/etc/nginx/conf.d/” 폴더를 사용합니다.

이제 nginx를 설정한 파일인 “default.conf”을 “nginx/asset”폴더에 작성합니다.

server {
   listen 80;
   root /var/www/html/public;
   index index.html index.htm index.php;

   server_name localhost;
   client_max_body_size 10M;

   error_log /var/log/nginx/error.log;
   access_log /var/log/nginx/access.log;

   location / {
       try_files $uri $uri/ /index.php?_url=$uri&$args;
   }

   location ~ \.php$ {
       try_files $uri =404;
       fastcgi_split_path_info ^(.+\.php)(/.+)$;
       fastcgi_pass php:9000;
       fastcgi_index /index.php;
       fastcgi_connect_timeout 60s;
       fastcgi_read_timeout 60s;
       fastcgi_buffers 256 4k;
       include fastcgi_params;
       fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
       fastcgi_param PATH_INFO $fastcgi_path_info;
   }
}

docker-compose에서 외부 포트를 80에서 내부 포트 80으로 연결했으니 listen은 80으로 합니다.
root가 “/var/www/html/public”인 이유는 Phalcon의 폴더구조 때문입니다.
로그를 기록하기 위한 경로를 각각 기재 한 뒤 location을 작성합니다.
여기서 가장 중요한 부분은 “fastcgi_pass” 입니다. 꼭 php가 들어가있는 컨테이너 명과 포트를 적어야 합니다. “컨테이너이름:포트"로 적으면 docker내에서 컨테이너 이름의 주소를 찾아 해당 주소의 포트에 연결됩니다. PHP는 기본적으로 9000포트를 사용하기 때문에 9000포트에 연결해주시면 되겠습니다.

docker-done.png

명령이 정상적으로 동작하고 나면 위와같은 화면을 볼 수 있습니다.
이제 `docker-compose ps`를 사용해 올라간 컨테이너들의 상태를 확인합니다.

docker-ps.png

위와같이 state가 up이고 ports가 정상적으로 연결되어있다면 성공입니다.
이제 기본적인 절차는 끝났습니다, 양이 많아서 docker-compose up 명령어 이후에 하는 설정에 대해서는 다음 글에서 설명하겠습니다.

Lovefield

Web Front-End developer

하고싶은게 많고, 나만의 서비스를 만들고 싶은 변태스러운 개발자입니다.