ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 도커를 이용하여 PHP 개발 환경 설정하기
    분석과탐구 2023. 5. 3. 19:59

    도커를 이용한 PHP 개발 환경 구축의 이점

    https://www.docker.com/

    도커를 이용한 개발, 배포 환경 구성의 이점은 무엇일까. 재사용하기 좋다는 것이 가장 크지 않나 싶다. 재사용하기 좋다는 것은 다음과 같다. 한 명의 프로그래머가 도커 기반으로 개발환경을 꾸미면 나머지 사람들은 그대로 사용하면 된다. 나머지 사람들은 같은 팀원일 수도 있고 미래의 내가 될 수도 있다. 그리고 이렇게 올려놓은 개발환경에 설정파일을 바꿔 서비스에도 올릴 수 있고.

     

    개발환경을 꾸민다는 것은 단순히 IDE만을 설치하는 것이 아니라 프로그램을 실행하기 위한 라이브러리나 시스템 도구, 런타임 등 필요한 것들을 구성하는 것을 의미한다. 따로 세팅을 한다면, 똑같은 일을 여러 번 반복하게 되어 시간이 낭비된다. 그리고, 시스템에 기본적으로 적용된 버전 차이에 따른 문제가 발생하기도 한다. 리눅스에 서로 다른 MCU를 위한 크로스 컴파일 환경을 구성하다가 GLIBC의 버전이 달라서 고생했던 적이 떠오른다.

     

    이것을 해결하기 위해선 VM을 써도 된다. 대신, VM의 생성 및 복사는 오랜 시간이 걸린다. 여러 프로그래머가 하나의 VM을 복사해서 공유하는 상황은 그렇게 좋진 않았다. 반면 도커는 그렇지 않다. 오로지 필요한 것은 도커를 설치하고 이미지를 가져와 컨테이너를 실행하는 것이다.

     

    기존 PHP 개발 환경에는 XAMPP, MAMP, WAMP가 있다. 이들은 매우 간단하게 설치할 수 있고 또 바로 개발하기에도 좋지만 두 가지 단점이 있다. 첫 번째는 로컬 머신에 하나의 글로벌 개발환경으로만 구성할 수 있다는 점이다. 만약 PHP를 기반으로 한 여러 프로젝트를 하나의 로컬머신에서 개발한다면, 환경 설정을 추가로 해야 한다. 두 번째는 개발환경과 배포환경이 차이가 난다는 것이다. 이것으로 인하여 잠재적으로 문제가 발생할 수 있다.

     

    https://aws.amazon.com/ko/docker/

    도커는 위와 같은 문제를 모두 해결한다. 이미지와 컨테이너 기반이기에 개발 환경과 배포 환경에 별다른 차이가 없다. 또한 여러 프로젝트를 동시에 개발한다고 해도 문제가 없다. 컨테이너는 다른 컨테이너와 그리고 호스트와 격리되기 때문이다.

     

    따라서 도커를 이용한 개발 환경 구성은 기존의 구성보다 초기 러닝커브가 있지만, 배워둘 만하다. 다음 글들은 도커 PHP 공식 이미지를 이용하여 구성을 진행하며 정리한 것이다.

    도커에 대한 개념 잠깐

    • 도커: 도커 역시 운영체제 위에서 동작하는 프로그램이다. 경량화된 VM이라고 생각해도 좋다. VM과 유사하지만, 가장 큰 차이점은 VM이 OS까지 가상화한다면, 도커는 호스트 OS를 그대로 사용한다는 점이다. 이미지를 기반으로 컨테이너를 실행한다. 

    • 이미지: 프로그램 빌드, 실행, 배포하기 위한 모든 것들을 포함하는 패키지이다. 소스, 라이브러리, 런타임 등등이 정의된 이미지가 컨테이너에 올라간다. 도커 이미지는 Dockerfile로 정의된다. Dockerfile을 빌드(docker build)하여 이미지로 생성할 수 있다. 혹은 다른 사람이 미리 정의한 이미지를 가져올 수도 있다.

    • Dockerfile: 이미지를 생성하기 위한 텍스트 파일이다. 특정 명령어를 실행하고, 호스트 파일을 복사하고, 컨테이너가 어떤 포트를 열지… 등등의 명령어로 구성된다.

    • 컨테이너: 컨테이너는 도커 이미지가 실행되는 단위이다. 호스트와 독립된 격리된 상태이다. 때문에 도커와 도커이미지만 있다면, 어느 환경에서든 실행할 수 있어 이식성이 좋다.

    • 컴포즈: 도커 컴포즈는 여러 컨테이너를 하나의 서비스로 다루기 위한 개념이다. 이미지 하나에 필요한 모든 소프트웨어와 소프트웨어를 동작하기 위환 환경을 꾸민다면, 하나의 컨테이너만으로 서비스를 제공할 수 있을 것이다.

      하지만, 이 모든 것들이 비용이기에 다른 사람들이 이미 만들어 놓은 이미지를 사용하기 마련이다. 컨테이너는 하나의 이미지만을 사용하므로, 다른 사람들이 이미 만들어 놓은 이미지를 사용하게 된다면, 서비스를 제공하기 위해 다수의 컨테이너를 사용하게 된다.

      그리고 이 다수의 컨테이너를 수동적으로 하나하나 다루기보다는 하나의 서비스로 묶어서 자동적으로 다루기 위한 방법이 바로 도커 컴포즈이다. 도커 컴포즈를 위해 docker-compose.yml 이라는 파일을 구성한다.

    docker + PHP로 개발 환경 세팅

    PHP를 위한 도커 공식 이미지가 존재한다. PHP는 내장된 웹서버를 이용하여 단독으로 실행될 수 있다. 그러나, 대부분의 경우 웹 서버(apache, nginx 등)와 데이터베이스(MySQL, Maria 등)와 함께 사용된다. 그래서 이미지 역시 apache를 포함한 이미지가 존재한다.

     

    일단 한 번 해본다. 같은 폴더에 다음 두 파일 Dockerfile, index.php를 생성한다.

    [Dockerfile]

    FROM php:8.2-apache  
    COPY . /var/www/html

    [index.php]

    <?php  
        phpinfo();  
    ?>

    이 폴더에서 다음 명령어를 실행한다.

    1. docker build -t docker-php .

    2. docker run -d -p 0.0.0.0:53333:80 docker-php

     

    첫 번째 명령어는 docker-php라는 이미지를 빌드하는데, 그 재료로 현재 폴더(.)를 사용하란 의미이다. Dockerfile과 index.php를 재료로 이미지가 생성된다.

    두 번째 명령어는 빌드한 이미지 docker-php를 이용하여 컨테이너를 실행한다. -p는 publish의 약자로 포트맵핑을 할 수 있다. -d는 detach의 약자로 -d 없이 실행하면 해당 shell은 컨테이너 실행 전용으로 쓰지만, -d 옵션을 붙이면 실행 후 shell을 그대로 쓸  수 있다.

     

    실행 후 localhost:53333로 접속하면 phpinfo의 화면이 나와야 한다.

    localhost:1235로 접속하면 나와야 할 화면

    도커 컨테이너에 직접 커맨드를 입력하고 싶다면 다음 명령어를 사용한다.

     

    docker exec -it 도커컨테이너ID 사용할shell

    docker exec -it brave_swanson bash

     

    도커컨테이너 ID는 도커 이미지를 실행하는 컨테이너의 ID이다. docker container ls로 실행 중인 컨테이너들의 정보를 알 수 있다. 사용한 shell은 bash sh 등이 있다. 

     

    어떤 커맨드를 입력해 볼까. 기본적인 것들을 확인했으니, 나중에 설정을 수정하기 위하여 apache와 php의 설정파일 위치를 알아내면 좋을 것 같다.

     

    먼저 php의 위치는 다음 커맨드로 찾을 수 있다.

    which php

    php.ini의 위치를 알아내기 위한 명령어는 다음과 같다.

    php --ini | grep php.ini

    php.ini 위치는 /usr/local/etc/php 이다.

    apache의 설정 파일은 어디 있을까?

    apache2 -V | egrep "(HTTPD\_ROOT|SERVER\_CONFIG\_FILE)"

    apache2.conf의 위치는 /etc/apache2/

    PHP extesnion

    도커 기반 php에서 확장 모듈을 설치하는 방법 하나를 소개하고 전체 흐름을 보려 한다. 미리 정의된 커맨드로 docker-php-ext-... 와 같은 것들이 있다. docker-php-ext-install, docker-php-ext-enable 등이 그것들이다. 나누어서 읽어보면, 바로 어떤 용도인지 알 수 있을 것이다.

    위 커맨드를 이용하여 확장 모듈을 설치할 수 있다. 다음은 그 예시이다.

    docker-php-ext-install mysqli && docker-php-ext-enable mysqli

     

    이후 php -m | grep mysqli 커맨드를 쳐보면 mysqli 확장이 설치된 걸 알 수 있다. php.ini에는 반영이 되었을까? php.ini에는 반영이 안 되고 conf.d 디렉토리 안에 확장모듈로 존재한다.

    conf.d 디렉토리 안에 있는 mysqli 확장

    PHP의 초기화 방식은 php.ini을 읽어온 후, 그다음 conf.d 디렉토리 안에 있는 ini파일들을 읽어와서 php.ini에 덮어씌우는 방식이다. 따라서 위와 같은 방식은 conf.d에 설정 파일을 추가하여 기존 php.ini를 수정하지 않고 새로운 설정을 추가하는 방향인 것이다.

    php.ini

    docker php를 설치해 보면 php.ini파일이 없다. 대신 두 파일이 존재한다.

    각각 php.ini-development php.ini-production이다. 이름만 봐도 하나는 개발용이고 하나는 서비스용인 것을 알 수 있다.

    환경변수나 스크립트를 통해서 둘 중 하나를 php.ini로 변경하면 될 것이다. 그렇다면 구체적으로 무엇이 다른 것일까?

    git을 이용하여 diff를 해보았다.

    php.ini-development와 production의 차이

    좌가 development 우가 production이다. 생각보다 크게 다르진 않다.

    차이점을 하나하나씩 보자.

    1. 예외 상황에서 stack trace 생성할 때 argument를 포함/불포함

    2. 에러 보여주기/안 보여 주기

    3. mysql 통계 정보 모으기/안 모으기

    4. compile assertion 켜기/끄기

    디버깅 제외하고 개발 환경 꾸미기

    PHP 디버깅을 할 때 xdebug와 같은 것을 이용하는데, 이것을 제외하고 일단 개발환경을 구성한다. 개발환경 설정하다가 너무 지칠 수 있다. 그 전에 한 번 여태까지 알아온 것들을 정리해보자.

     

    1. 도커 PHP 공식 이미지를 이용하여 웹서버와 PHP를 포함한 컨테이너를 실행할 수 있다.

    2. 내가 작성한 코드를 컨테이너에 옮겨서 페이지를 확인할 수 있다.

    3. 확장 모듈을 설치하기 위한 커맨드가 따로 존재한다.

    4. ini파일은 2가지가 있고, 상황에 따라 설정을 하면 된다.

     

    이제 일반적인 개발을 하는 과정을 상상해 보면 다음과 같다.

    1. 개발 환경 구성

    2. 코딩 -> 코딩 결과(페이지, API리턴) 확인

    3. 수정

    4. 2,3 반복

     

    2와 3을 반복해야 하는데, 지금처럼 도커로 개발환경을 꾸미면 어렵다. 왜냐하면 로컬머신에 있는 소스파일을 수정해도 컨테이너에 바로 반영되지 않기 때문이다. 따라서 소스 파일 수정이 즉각 도커 컨테이너에 반영될 필요가 있다. 이를 위한 방법 중에 하나가 마운트이다. 컨테이너를 실행할 때 로컬 머신과 컨테이너에서 마운트 할 디렉터리를 연결해 준다

     

    -v local_path:container_path

    ex) docker run -v ./src:/var/www/html php-ext

     

    다만 아쉬운 점이 하나 있다면, 마운트 하는 위 플래그를 Dockerfile 내부에서 정의할 방법을 찾지 못하였다. 대신 도커 컴포즈를 이용하여 설정을 할 때는 스크립트 차원에서 마운트를 지정할 수 있다. Dockerfile은 docker container 내에서 실행하는 일련의 동작만을 정의하고 호스트와의 커뮤니케이션은 하지 않는 방향으로 보인다.

     

    정리하면, 다음과 같은 Dockerfile이 나온다.

    FROM php:8.2-apache
    
    RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
    RUN pecl install xdebug && docker-php-ext-enable xdebug
    
    RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

    $PHP_INI_DIR는 php:8.2-apache에서 정의된 환경변수이다. 그리고 다음과 같은 도커 커맨드로 빌드하고 실행한다.

    sic> docker build -t php-ext .  
    docker run -d -p 0.0.0.0:8080:80 -v ./src:/var/www/html php-ext

    여기까지 하면 최소한의 개발 환경은 작성된 것이다.

    로컬에서 파일 인식하기

    도커 기반으로 개발을 하면 로컬에 PHP를 설치하지 않아도 된다. 다음 도식도를 보자.

    하지만, 코드 인텔리전스가 제대로 동작하지 않을 수 있다. 단순히 텍스트 에디터만 쓴다면 상관없지만, IDE의 편리성을 포기할 이유가 없다. 그러므로 로컬에 PHP를 설치하고, IDE에서 지정하는 대로 설정을 일부 해준다면 편하게 개발할 수 있다. 혹은, IDE 차원에서 PHP 설치 없이도 버전을 지정하기만 해도 인텔리전스가 작동하기도 한다.

     

    PHP스톰의 경우 설정(ctrl+alt+s)를 누르고 PHP탭을 누르면 바로 보인다. PHP를 설치하고 경로와 최소 지원 버전을 설정하면 된다. 그리고, PHP탭 안의 Analysis에서 $_SERVER['DOCUMENT_ROOT']까지 지정해 주면 된다. 보통 프로젝트의 폴더 루트와 도커와 volume으로 매핑할 디렉토리가 다르므로, 해당 폴더를 지정해 주면 된다.

    참고

     

    댓글

Designed by Tistory.