Tempo Di Valse

[Docker] Nginx + PHP-FPM 이미지를 만들어보자 (2편) 본문

개발/ETC

[Docker] Nginx + PHP-FPM 이미지를 만들어보자 (2편)

TempoDiValse 2022. 6. 27. 18:00
 

[Docker] Nginx + PHP-FPM 이미지를 만들어보자 (1편)

Docker 자체를 처음 사용 해본 지라, 컨테이너를 섞어서 쉽게 구성할 수 있다고 해서 시도해 봤는데 실패했다. 게다가 PHP 버전들이 내가 사용하고 싶은 8버전 이상의 FPM 들이 검색을 못 한건지 안

tempodivalse.tistory.com

1편에 이어서 이번 포스팅은 Nginx 와 PHP-FPM 의 세부 설정 파일을 마무리 짓는 내용을 작성해보려 한다.

 

1. Nginx 필수 설정 파일

 

Nginx 를 써봤다면, nginx.conf 파일이 메인 설정 파일이라는 것은 알고 있을 것이다. 몇개의 conf 를 만들었더라도 메인은 nginx.conf 이기 때문에 include 되지 않으면 해당 conf 에 대해서는 실행이 되지 않을 것이다. 그렇다고 많은 양의 설정들을 nginx.conf 에 넣는 것은 비효율적이기 때문에 유연하게 변경을 해보도록 한다.

 

우선, 저번 포스팅에서 Docker 작업을 위한 폴더 구성을 할 때 만들었던 conf 를 다음과 같이 구성해보았다.

- ./conf.d : 설정의 목적에 맞는 아이들이 들어갈 것이다. 
- ./default.d : 웹 서비스 명세에 기본적으로 있어야 하는 아이들이 들어갈 것이다.
- ./site-available : 웹 서비스별 명세가 들어갈 것이다.

일단, site-avaliable 에 들어갈 웹 서비스 명세를 작성해보자.

# ./site-available/service.conf

server {
    listen 80 default_server;
    server_name _;
 
    root /usr/share/nginx/html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    include /etc/nginx/default.d/*.conf;
}

include 를 통해 default.d 에 있는 기본적인 아이들을 포함 시킬 것이다. 서버에서 작동할 것이기 때문에 경로들 또한 로컬 경로가 아닌 서버 시점에서 바라보는 경로로 설정해 주도록 한다.

 

다음으로는 default.d 에 php 확장자가 들어가면 인식할 수 있도록 만들어주는 블록을 적을 것이다. 

# ./default.d/php.conf

index index.php index.htm index.html;

location ~ \.(php|phar)(/.*)?$ {
    fastcgi_split_path_info ^(.+\.(?:php|phar))(/.*)$;

    fastcgi_intercept_errors on;
    fastcgi_index  index.php;
    include        fastcgi_params;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_param  PATH_INFO $fastcgi_path_info;
    fastcgi_pass   php-fpm;
}​

 

 

 

추가적으로 index 페이지는 index.php index.html index.html 인 아이들만 되도록 명세를 해주고, location 블록을 통해서 php와 phar 파일을 따로 처리하도록 한다. 여기서 주목해야 될 곳은 fastcgi_pass 부분으로, 보통 여기에다가는 127.0.0.1:9000 형식으로 넣어주는데 나 같은 경우에는 upstream 을 정의해놓고 해당 upstream 으로 던져주도록 만들었다. 이 방식은 AWS EC2 에서 nginx 를 설치하는데 이렇게 되어있어서 방법을 익혀놓았다. upstream 은 미리 설정을 정의하는 것이기 때문에 conf.d 에 입력을 시켜놓았다.

# ./conf.d/php-fpm.conf

upstream php-fpm {
    server unix:/var/run/php-fpm/www.sock;
}

upstream 이름은 php-fpm 이기 때문에 위에 fastcgi_pass 도 php-fpm 으로 맞춰놓았다. 그리고 server 의 값은 127.0.0.1:9000 이 아닌 unix:/var/run/php-fpm/www.sock 을 적어놓았다. php-fpm 을 사용하게 된다면 127.0.0.1:9000 보다는 해당 방식이 훨씬 처리하는 속도가 빠르다고 하여 변경을 했는데 실제로 그 둘의 차이가 어떻게 되는 지는 눈으로 확인 해보진 못했다. 여튼 unix 방식을 사용하는 것을 대부분 추천하고 있기 때문에 이렇게 사용해 보도록 한다.

 

이제 이 모든 것들을 Nginx 에서 실행할 수 있도록 nginx.conf 에 작성을 해주어야 한다.

# nginx.conf

daemon off;

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/site-available/*.conf;
}

http 블록을 확인해보면 맨 마지막 줄에 include 두 줄을 작성하며 Nginx 설정을 끝을 내도록 한다.

 

2. PHP-FPM 필수 설정 파일

 

Nginx 만 되었다고 해서 PHP 가 동작하진 않는다. 로컬에서 작업하고 붙여 넣어 준 Nginx 와는 다르게 PHP-FPM 은 작동하는데에 몇가지 설정만 변경해주면 되기 때문에 따로 로컬에 파일을 작성하지 않고 스크립트로면 문자를 변경하여 처리하도록 작성했다.

 

각 필요 설정 파일들은 이미 Dockerfile 을 통해서 옮기고, 이름바꾸고 했을 것이다. 하지만 설정 파일 내부의 데이터들은 바꾸지 못했는데, 해당 작업을 Dockerfile 마지막에 넣어준 run-script.sh 파일을 통하여 실행할 것이다.

#!/bin/sh

set -eux

mkdir /var/run/php-fpm

sed -i 's/listen = 127.0.0.1:9000/listen = \/var\/run\/php-fpm\/www.sock/g' /usr/local/php/etc/php-fpm.d/www.conf
sed -i 's/;listen.owner/listen.owner/g' /usr/local/php/etc/php-fpm.d/www.conf
sed -i 's/;listen.group/listen.group/g' /usr/local/php/etc/php-fpm.d/www.conf
sed -i 's/;listen.mode/listen.mode/g' /usr/local/php/etc/php-fpm.d/www.conf

rc-service php-fpm start
nginx -t
nginx

Alpine 리눅스에서는 /bin/bash 가 아닌 /bin/sh 를 사용하여 스크립트를 짜는 것 같다.

 

set -eux 를 먼저 호출하였는데, e와 u 는 어떤 차이가 있는 지 확인은 못했지만 x 를 추가 하게 되면, 이미지를 컨테이너로 실행했을 때, 어떤 커맨드를 실행했는 지 눈으로 확인할 수 있다. 그래서 디버깅 용도로 꽤나 유용한 플래그라고 할 수 있다.

 

mkdir 를 통해서 /var/run/php-fpm 에 폴더를 생성해주었는데, Nginx upstream 설정할 때 /var/run/php-fpm/www.sock 파일을 바라보도록 설정을 해서, 없는 폴더이기 때문에 생성을 미리 해주어야 한다. www.sock 파일은 PHP-FPM 이 실행되면 자동으로 생성된다. (폴더가 없으면 에러가 발생한다.)

 

그 다음 sed -i 로 시작하는 4줄의 커맨드들이 있는데, 이 부분이 설정 파일 내에서 변경할 사항들을 적어놓은 곳이다. 바꾸는 파일은 전부 www.conf 파일 내부인데, sed 명령어 하나를 통하여 여러군데를 고치는 방법을 몰라 4부분에 걸쳐서 각 줄마다 고쳐보았다. 

 

먼저 첫번째 줄, listen = 127.0.0.1:9000 의 내용을 listen=/var/run/php-fpm/www.sock 으로 변경을 했다. 

2~4번째 줄, listen 앞에 있는 세미콜론을 삭제하여 주석이 아닌 상태로 변경하였다. 이 작업을 하지 않으면 php 주소를 입력했을 때 파일이 다운로드 되는 현상을 확인할 수 있었다.

 

수정까지 완료된 다음에 openrc 패키지에 있는 rc-service 를 통해서 php-fpm 을 실행시켰으며, 추가적으로 Nginx 의 설정에 문제가 있는지 확인하기 위해 nginx -t 를 하고 nginx 를 돌렸다.

 

비로소 이미지를 만들 준비는 모두 끝났다. 이제 컴파일 같은 작업을 하여 이미지를 생성해보자.

 

3. 이미지 생성

 

지금까지 Dockerfile 에 명세가 잘 되어있다면, 이미지를 만드는데 큰 문제는 없을 것이다. 그럼 바로 터미널로 이동하여 커맨드를 입력해보도록 하자. 터미널을 이용하여 Dockerfile 이 있는 작업폴더로 이동한 다음 다음의 커맨드로 실행을 한다.

docker build . --no-cache -t [IMAGE_NAME]

폴더 내에 Dockerfile 이 있다면 자동으로 감지하여 이미지를 생성해준다. 이미지 이름은 -t 옵션에 작성해주면 된다. 중간에 --no-cache 의 경우에는 실패하거나 뭐 해서 이미지를 다시 생성하는 경우에 기존에 물고 있던 데이터들을 다시 사용할 수 있기 때문에, Dockerfile 을 수정한 후 변경된 옵션들이 적용되지 않을 수 있어서 지정을 해주도록 한다.

Dockerfile 명세중에 시간이 제일 많이 잡아 먹는 부분이 단연 PHP 를 컴파일 할 때인데, 대략 600s 이상이었으니 10분 정도 잡아먹는 것 같다. 모든 작업이 끝나면 이미지를 컨테이너로 실행하는 부분만 남았다.

 

4. 실행

여기까지 되었으면 이미지 생성은 완료 되었고, GUI 에서도 이미지 항목에 만들어진 것을 볼 수 있다. 이제 해당 이미지를 컨테이너로 실행시켜 보도록 하자.

 

터미널에서 다음과 같이 입력을 한다.

docker run -d -p [PORT]:80 \
    --volume $(pwd)/html:/usr/share/nginx/html \
    --name [CONTAINER_NAME] \
    [IMAGE_NAME]

[PORT] 는 외부에서 컨테이너로 접속할 때 어떤 포트로 접속할 지를 정해주는 것이다. 만약 -p 2357:80 이라고하면 http://localhost:2357 로 브라우저에서 접근을 할 수 있게 된다. 컨테이너 내부에서는 80번 포트를 통해 접근하는 것으로 알고 있게 된다.

 

--volume 은 로컬 폴더를 이미지 내의 폴더에 마운트 시키는 것인데, 형식은 --volume [로컬 경로]:[이미지 내 경로] 가 된다. Dockerfile 에 /usr/share/nginx/html 로 VOLUME 을 통해 지정을 했기 때문에 이 값을 [이미지 내 경로]에 작성 해주고, [로컬 경로] 는 절대주소를 작성해주면 된다. $(pwd) 를 통해서 현재 위치의 폴더값을 가져와서 집어넣었다.

 

--name 은 컨테이너의 이름을 정해주면 된다

 

마지막으로 어떤 이미지를 사용할 것인지 입력하고서 엔터를 치면 컨테이너가 실행이 될 것이다.

작업 폴더의 html 폴더에 index.php 를 만들어주고 phpinfo() 를 실행시켜 테스트 페이지가 잘 작동되는 지 확인해보도록 하자.

 

잘 나오면 성공!!

 

 

반응형
Comments