도커 컨테이너 환경으로 APM 구축하기

이 장은 도커 이미지를 생성하고 푸시push하는 방법을 살펴보고 APM(Apache, PHP, MySql)을 구축해 봅니다.



이 장의 내용

  • 도커 이미지를 만듭니다.
  • 만든 도커 이미지를 푸시push합니다.



만약 컨테이너를 통해 웹 서버WEB Server를 구성하려면 어떻게 해야 할까요?


그림 컨테이너로 생성한 웹 서버의 구조


ubuntu:14.04 이미지를 통해 web-demo라는 이름의 컨테이너를 생성합니다.

$  docker run -itd -p 80:80 --name web-demo ubuntu:14.04


-p 옵션은 도커 호스트와 바인딩 되는 포트를 정의합니다. 예컨대 8080:80 도커 호스트에서 docker-proxy 데몬을 통해 8080 포트를 컨테이너의 80 포트로 전달할 수 있습니다.

-itd 옵션은 i 표준 입력을 활성화합니다. t는 TTY Mode로, d는 백그라운드로 컨테이너를 실행하라는 의미입니다.

$ docker ps -a
CONTAINER ID        IMAGE COMMAND             CREATED STATUS         PORTS NAMES
b4869ec43157        ubuntu:14.04 "/bin/bash"         7 seconds ago Up 6 seconds         0.0.0.0:80->80/tcp web-demo
2e4d989d8651        ubuntu:14.04 "/bin/bash"         7 minutes ago Exited (130) 6 minutes ago                        ubuntu-awskrug
491da6daefba        ubuntu:14.04 "/bin/echo hello"   12 minutes ago Exited (0) 12 minutes ago                         modest_gates


생성한 web-demo 컨테이너에 접속합니다.

$ docker exec -it web-demo /bin/bash


ubuntu 14.04의 minimal 이미지이므로, 다음 명령으로 웹사이트 구동에 필요한 필수 패키지를 내려받고 설치합니다.

root@e5b7d7c666d1:/# apt-get update
root@e5b7d7c666d1:/# apt-get install -y apache2 php5 mysql-server php5-mysql php5-curl git
root@e5b7d7c666d1:/# cd /var/www/html
root@e5b7d7c666d1:/# git clone https://github.com/blueice123/web-demo


필수 패키지를 설치했다면 MySQL과 아파치 웹 서비스를 구동합니다.

root@e5b7d7c666d1:/# service mysql start
root@e5b7d7c666d1:/# service apache2 start


MySQL에 필요한 데이터베이스Database와 사용자User를 생성한 후 생성된 계정에 권한을 부여합니다.

root@e5b7d7c666d1:/# mysql -u root -p
mysql> CREATE DATABASE web_demo;
mysql> CREATE USER 'username'@'%' IDENTIFIED BY 'password';
mysql> GRANT ALL PRIVILEGES ON web_demo.* TO 'username'@'%';
mysql> quit


생성한 데이터베이스에 미리 만들어 둔 덤프dump 내용을 밀어넣습니다.

root@e5b7d7c666d1:~# cd /var/www/html/web-demo/
root@e5b7d7c666d1:/var/www/html/web-demo# mysql -u username -p web_demo < web_demo.sql
Enter password: password


config.php 파일 내 DB connection 부분을 앞의 MySQL 설정과 같이 변경합니다.

root@e5b7d7c666d1:/var/www/html/web-demo# vi ./config.php      
....
// Database connection parameters  <-- DB connection 설정 부분 변경
$db_hostname = "localhost";
$db_database = "web_demo";
$db_username = "username";
$db_password = "password";
....


아파치 프로세스가 uploads 디렉터리를 사용할 수 있도록 권한을 부여합니다.

root@e5b7d7c666d1:/var/www/html/web-demo# chown -R www-data:www-data uploads/


이후 다른 컨테이너가 재시작restart하더라도 아파치 웹 서버가 자동으로 시작되도록 설정합니다.

root@e5b7d7c666d1:/var/www/html/web-demo# service apache2 restart


웹 브라우저에서 만든 웹 서버에 접속해 봅니다. 주소는 다음과 같습니다.

  • http://<Docker Host Public IP>/web-demo/


힘들게 하나의 컨테이너를 생성했지만, 이 아키텍처에는 큰 문제가 있습니다. 바로 데이터베이스의 DATA와 업로드upload되는 파일file의 경로가 컨테이너 내부에 있다는 문제입니다.

도커 측은 컨테이너 안에 의미 있는 데이터를 저장하지 말 것을 권장하고 있습니다. 이 문제를 해결하려면 어떻게 해야 할까요?

결론적으로는 아키텍처를 다음 그림과 같이 변경해야 합니다.


이렇게 아키텍처를 변경하면  컨테이너 내부에는 저장되는 데이터 없이  웹 서비스만 순수하게 구동할 수 있습니다. (여기서는 시간 관계상 함께 구현하지는 않습니다.)



  [TIP] 컨테이너 내 로그 관리 팁

궁금해하실 분을 위해 컨테이너 내에서 로그를 관리하는 방법을 정리한 문서를 공유합니다.

https://docs.docker.com/config/containers/logging/



도커 이미지 만들기

하나의 서비스를 구동하는 데 이렇게  복잡한 절차를 거쳐야 한다면 굳이 도커를 사용해야 할까요? 도커를 사용하면 애플리케이션에 필요한 개발 환경과 애플리케이션을 저장한 채로 이미지를 빌드할 수 있고, 빌드된 이미지는 플랫폼에 구애 받지 않고 도커 환경이라면 배포할 수 있습니다. 그래서 다들 도커를 사용하는거죠.

지금부터는 도커 이미지를 만들어 보겠습니다. 도커 이미지 빌드build 방법은 크게 두 가지입니다.


  1. 완성한 컨테이너를 $ docker commit 명령으로 이미지로 만든다

  • 이 방법은 소스 배포 등으로 컨테이너 내부 파일이 변경돼 이미지를 새로 빌드해야 할 때 사용합니다.

      2. dockerfile을 작성 후 이미지로 빌드한다

  • 이 방법은 처음 컨테이너를 만들어 운영 혹은 개발 환경을 정의할 때 주로 이용합니다.


먼저 첫 번째 방법으로 완성한 컨테이너를 이미지로 만들어 보겠습니다.

$ docker commit 명령은 컨테이너 내 변경사항을 이미지 파일로 만드는 명령입니다.

$ docker commit -a “작성자 명” -m “메시지 내용” container_name image_name:TAG


web-demo 컨테이너를 기준으로 하는 이미지 web-demo:0.1을 생성하라는 뜻입니다.

$ docker commit -a "SYHA <blueice_123@naver.com>" -m AWSKRUG web-demo web-demo:0.1


$ docker commit 명령의 옵션은 다음과 같습니다.

옵션

설명

비고

-a

--author=" "
생성자(작업자) 정보를 기입합니다.


-m

--message=" "
이미지의 메시지입니다.


-p

--pause=true/false 이미지를 생성할 때 컨테이너를 중지(stop)한 뒤 커밋할 것인지에 대한 정의입니다. 기본값(default)은 false, 즉 중지하지 않고 이미지를 생성합니다.



도커 이미지의 용량을 보면 우리가 사용한 우분투 14.04 운영체제 이미지보다 용량이 더 큰 것을 확인할 수 있습니다.

$ docker images
REPOSITORY          TAG IMAGE ID            CREATED SIZE
web-demo            0.1 1472a0eb9911        3 seconds ago 456MB
ubuntu              14.04 0b1edfbffd27        4 weeks ago 113MB


두 번째 방법은 Dockerfile 이라는 파일을 통해 이미지를 빌드하는 것입니다. 여기서는 간단한 Dockerfile 문법만 확인하고 넘어가겠습니다.

도커 호스트 서버에서 다음 명령으로 Dockerfile을 생성하면 됩니다.

$ mkdir ~/AWSKRUG-Docker

$ vi ~/AWSKRUG-Docker/Dockerfile
FROM ubuntu:14.04

## AWSKRUG 2018.05.20 by Juny, syha
MAINTAINER name <email@domain.co.kr>

# Avoid ERROR: invoke-rc.d: policy-rc.d denied execution of start.
RUN sed -i "s/^exit 101$/exit 0/" /usr/sbin/policy-rc.d

## Install packge
RUN apt-get update && apt-get install -y apache2 php5 php5-mysql php5-curl git
RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf

## Copy web-demo source code
WORKDIR /var/www/html
RUN git clone https://github.com/blueice123/web-demo

## DB Connection information
ENV MYSQL_HOST='"username.c6gradmwj7dj.ap-northeast-2.rds.amazonaws.com";' \
   MYSQL_USER='"username";' \
   MYSQL_USER_PASS='"password";' \
   STORAGE_OPTION='"s3";' \
   S3_REGION='"ap-southeast-2";' \
   S3_BUCKET='"awskrug-docker";' \
   S3_BASEURL='s3-ap-southeast-2.amazonaws.com'

WORKDIR /var/www/html/web-demo

## Service auto start
RUN update-rc.d apache2 defaults
RUN update-rc.d apache2 enable

## Port
EXPOSE 80

## Start the service
CMD /usr/sbin/apache2ctl -D FOREGROUND


Dockerfile 작성 문법

명령어

설명

비고

FROM

생성할 이미지의 베이스base가 될 이미지를 뜻합니다. 반드시 한 번은 입력해야 하며, 이미지가 없을 경우 자동으로 이미지를 pull 합니다.


MAINTAINER

이미지를 생성한 개발자의 정보를 나타냅니다.


RUN

이미지를 만들기 위해서 컨테이너 내부에서 명령을 실행합니다.

이때 Y/N 등 대화 형태로 동작하게 되면 에러error가 발생합니다.

옵션에 -y를 넣어줍니다.

ADD

파일을 이미지에 추가합니다.

예를 들어 다음 명령은 test.html의 파일을 /var/www/html에 추가합니다.

예) ADD test.html /var/www/html


COPY

파일을 이미지에 추가합니다.

COPY <복사할 파일 경로> <이미지에서 저장될 파일 위치>

주의할 점은 복사할 파일 경로는 Dockerfile 경로를 벗어날 수 없다는 점입니다.

또한 추가된 파일은 소유자, 그룹이 0(root)로 정의되며 퍼미션permission은 그대로 상속 받습니다.

COPY는 ADD와 달리 압축 파일을 추가할 때 이미지에 압축 파일을 그대로 위치할 수 있습니다.

WORKDIR

bash shell의 cd 명령과 같습니다. 작업할 위치를 정의합니다. 여러 번 사용할 수도 있습니다.


ENV

컨테이너 내 환경변수를 선언합니다.


EXPOSE

이미지에서 노출할 포트를 설정합니다. 이 옵션은 단지 컨테이너의 해당 포트를 사용하겠다고 선언하는 것이지 호스트와 바인딩되는 것은 아닙니다.

만약 호스트와 바인드하자 한다면 docker run -p 80:80 등으로 run할 때 -p, -P 옵션을 정의해야 합니다.

CMD

컨테이너가 시작될 때마다 실행할 명령어를 정의합니다. Dockerfile에서 한번만 사용할 수 있습니다.



# docker build --tag {image_tag:version} {docker_file 파일위치}
$ docker build --tag web-demo:0.2 ~/AWSKRUG-Docker/



  [TIP] 만약 다음과 같은 에러가 발생한다면?

unable to prepare context: context must be a directory: {docker file 위치}


Dockerfile의 이름 혹은 Dockerfile을 가르키는 위치가 잘못되어서 에러가 발생했을 가능성이 높습니다. Dockerfile 파일명 또는 {docker file 위치}에 상위 디렉터리를 지정했는지 재확인합니다.

[root@ip-172-31-28-248 home]# docker build --tag web-demo:0.2 ~/AWSKRUG-Docker/


혹은

[root@ip-172-31-28-248 home]# docker build --tag web-demo:0.2 . <- .(dot) 현재 Directory


하위 디렉터리에 있는 불필요한 파일은 .dockerignore 파일을 생성해 제외할 수 있습니다.

$ vi ~/AWSKRUG-Docker/.dockerignore

.git

.ipynb_checkpoints/*
/notebooks/*
/unused/*

Dockerfile
.DS_Store
.gitignore
README.md
env.*
/devops/*

# To prevent storing dev/temporary container data
*.csv
/tmp/



도커 이미지 push

변경된 설정과 소스 파일이 모두 포함된 이미지가 만들어졌습니다.

이미지를 가지고 있는 도커 호스트Docker Host에서는 # docker run 명령으로 컨테이너를 여러 대를 만들 수 있습니다. 하지만 여러 대의 도커 호스트를 클러스터링Clustering 했을 경우 해당 호스트Host에서 이미지를 가지고 있지 않으면 컨테이너를 생성하지 못합니다.

이런 경우를 대비하기 위해 Dockerfile을 공유해 가지고 있거나, 빌드된 이미지를 도커 허브 등을 통해 업로드한 후 이미지 자체를 공유하는 방법을 생각할 수 있습니다.


  1. 먼저 도커 허브(https://hub.docker.com)에서 리포지터리Repository를 생성합니다.


도커 리포지터리를 생성한 후 리포지터리 이름name에 맞게 이미지를 다시 빌드합니다.

이미지 이름Image name을 다음과 같이 정의해야 도커 허브에 push가 됩니다.

DockerHubID/DockerHubReponame:TAG


$ docker commit -a "생성자" -m 멘트 web-demo <DockerHubID>/web-demo:0.3

혹은

$ docker build -t <DockerHubID>/web-demo:0.3 ~/AWSKRUG-Docker/
$ docker push <DockerHubID>/web-demo:0.3


업로드된 결과는 도커 허브에서 확인할 수 있습니다.


이밎 업로드가 완료됐다며느 삭제한 다음 다시 내려받아 봅시다.

$ docker rmi <DockerHubID>/web-demo:0.3



  [TIP] 참고하세요!

$ docker rm <container>
$ docker rmi <images>



$ docker pull <DockerHubID>/web-demo:0.3
$ docker images
REPOSITORY            TAG IMAGE ID            CREATED SIZE
blueice123/web-demo   0.3 504df8136b98        26 minutes ago 330MB


다음 실습을 위해 실행 중인 컨테이너는 모두 중단stop합니다.

$ docker stop $(docker ps -a -q)



 [한빛미디어 도커Docker 도서 보러가기]