Docker 기반 개발환경 구축

본 글은 XE OpenSeminar #1에서 진행한 세션의 내용을 정리한 글입니다. 해당 세션의 발표 영상은 XE youtube 채널에서 보실 수 있고 발표 자료는 XE SlideShare에서 다운로드 받으실 수 있습니다.



Image와 Container를 사용하기 위한 간단한 명령어부터 보도록 하겠습니다.

docker search라는 명령어는 전세계의 많은 사용자들이 만들어서 공유하는 image와 docker hub에서 공식적으로 제공하는 image를 검색할 수 있습니다.

위 그림은 ubuntu image를 docker search 명령어를 통해서 검색한 화면입니다. official이라는 부분에 OK가 적혀있고 name에 특별한 repository의 이름 없이 ubuntu라고만 적혀있는 image는 docker hub에서 공식적으로 제공하는 image입니다. 아래에 repository가 적혀져 있는 image는 다른 사용자가 만들어서 공유하는 image입니다.

docker search를 사용해서 검색한 image는 docker pull이라는 명령어를 통해서 다운로드 받을 수 있습니다. docker pull ubuntu라는 명령어를 실행하면 특별한 tag가 지정되지 않았기 때문에 자동적으로 docker pull ubuntu:latest image가 다운로드 됩니다. 오른쪽 화면처럼 docker pull ubuntu:14.04라는 tag를 지정하면 14.04 tag가 지정된 image를 다운 받을 수 있습니다.

docker images 명령어를 실행하면 현재 컴퓨터에 다운로드 받아서 저장되어 있는 image의 목록을 볼 수 있습니다.

오른쪽 화면은 ubuntu:latest image와 ubuntu:14.04 image가 저장되어 있는 화면입니다.

docker create 명령어를 사용하면 docker pull 명령어로 다운로드 받은 image를 사용해서 container를 만들 수 있습니다.

docker create 명령에서 -i 옵션은 컴퓨터의 STDIN과 생성된 STDIN을 연결해서 컴퓨터가 입력받는 내용을 container로 입력해 주는 옵션이고 -t 옵션은 container에 terminal을 할당하는 옵션입니다. -i와 -t는 2가지의 옵션을 같이 사용해야 원하는 결과를 얻을 수 있기 때문에 보통 -it 이렇게 붙여서 사용합니다.

— name 옵션은 생성하는 container에 이름을 지정할 때 사용합니다.

docker ps 명령어는 container의 목록을 출력하는데 사용합니다. -a 옵션은 container의 상태에 상관 없이 모든 container의 목록을 출력할 때 사용합니다.

docker create 명령어로 container를 생성 후 docker ps -a 명령을 실행하면 Created 상태인 — name에서 지정한 이름인 ubuntu_init이라는 이름을 가진 container가 생성된 것을 확인할 수 있습니다.

docker start 명령어로 정지 상태인 container를 실행할 수 있습니다. docker start 명령과 함께 container의 정보를 넘겨줘야 하는데 위 화면은 container의 name을 지정해서 docker start 명령을 실행한 화면입니다. container의 id로도 실행이 가능 하기 때문에 위 화면에서 docker start fb65a599bc8c을 실행해도 같은 결과를 얻을 수 있습니다.

docker attach 명령어는 실행 상태인 container에 접근할 수 있습니다. container를 생성할 때 -it 옵션을 지정했기 때문에 docker attach 명령어를 실행하면 ubuntu의 bash에 접속 할 수 있습니다.

docker run이라는 명령어는 위에서 실행 했던 명령들을 간편하게 하나의 명령어로 실행할 수 있습니다.

기존에는 docker pull -> docker create -> docker start -> docker atttach 명령어를 사용해서 image를 container로 만들고 container를 시작시키고 container에 접근하는 명령어들을 사용해서 container에 접속했지만 docker run 명령어를 사용하면 한 번의 명령어로 위 과정을 생략할 수 있습니다.

보통 image를 받으면서 바로 container를 생성해서 사용하기 때문에 docker run 명령어를 많이 사용합니다.

docker run과 docker create는 command라는 옵션을 지정할 수 있는데 오른쪽 아래 화면에 위 명령은 command 옵션을 생략해서 기본적으로 지정되어 있는 ubuntu의 bash에 접속된 화면이고 아래는 echo hi 라는 command를 지정한 화면입니다. 해당 command의 특징은 뒤에 나오는 Dockerfile 부분에서 다시 설명하도록 하겠습니다.

docker ps -a 명령어로 container의 상태를 보면 command를 지정한 container와 지정하지 않은 container의 차이를 볼 수 있습니다.

docker container 명령어는 container 관리 할 수 있습니다. prune이라는 command를 같이 사용하면 종료 상태인 container를 한번에 삭제 할 수 있습니다.

container를 개별로 삭제하려면 docker rm이라는 명령어를 사용해서 삭제할 수 있습니다.

지금까지 docker의 기본적인 명령어를 살펴봤는데 위에 보신것 처럼 docker를 사용하면 당장 ubuntu를 사용할 일이 있다면 별다른 컴퓨터나 다른 가상 머신 등을 사용하지 않더라도 docker와 간단한 명령어 몇가지로 ubuntu를 사용할 수 있습니다. ubuntu 이외에도 많은 image가 있기 때문에 필요할 때 바로 찾아서 사용할 수 있다는 장점이 있습니다.

이번에는 위에서 살펴본 명령어를 활용해서 XE3 Image를 만들어서 배포해 보도록 하겠습니다. Image를 만드는 과정에서 docker에 대해 설명이 필요한 부분을 더 설명하겠습니다.

진행 과정은 XE3를 사용 하려면 php, composer, xe3, apache 등이 필요한데 각각의 패키지를 설치한 image를 만들어서 버전관리까지 가능한 image를 만들어 보도록 하겠습니다.

먼저 앞에서 봤던 docker run 명령어를 실행해서 ubuntu:latest image를 사용하는 container를 만들어서 실행합니다.

아래에 나오는 apt-get으로 실행하는 명령어들은 docker와 별개로 ubuntu에서 패키지를 설치 하는 명령어 입니다. 모든 설치가 다 끝났을 때 php -v 명령어를 실행 후 위와 같이 php에 대한 정보가 출력된다면 정상적으로 php가 설치 된 것을 확인 할 수 있습니다.

php 설치 후 exit 명령을 실행해서 container에서 빠져나옵니다.

container에서 빠져 나온 후 docker ps -a 명령어를 실행하면 방금 php를 설치한 container가 종료 상태로 남아 있는 것을 확인할 수 있습니다.

php가 설치된 container를 image로 만들기 위해서 docker commit 명령어를 실행합니다. docker commit 명령어의 -m 옵션을 사용해서 image에 대한 설명을 기록합니다. image로 생성할 container의 지정은 docker start 명령어와 마찬가지로 container의 id나 name을 지정해서 image로 만들 수 있습니다.

마지막 인자는 image의 이름인데 생성한 image는 docker hub에 업로드를 할 예정이기 때문에 sirwoongke라는 제 계정, image 이름, tag를 결합해서 sirwoongke/xe3:0.1이라는 이름을 지정해서 image를 생성했습니다.

생성한 image를 docker hub에 업로드 하기 위하여 docker hub에 회원가입을 하고 docker login이라는 명령어로 login을 합니다.

password를 입력할 때는 linux와 마찬가지로 입력을 해도 화면의 변화가 없지만 입력한 비밀번호는 입력이 되고 있기 때문에 당황하지 말고 입력후 엔터키를 입력하시면 계정 정보가 맞다면 로그인을 할 수 있습니다.

docker에 로그인이 됐다면 docker push라는 명령어로 방금 생성한 image를 docker hub에 업로드 할 수 있습니다.

docker push 후 docker hub 사이트에 가보면 방금 push한 image로 repository가 생성된 것을 볼 수 있습니다.

처음 봤던 docker search 명령어로 docker hub에서 방금 push한 image를 찾으면 검색이 되지 않는데 docker hub 사이트에서 short description 부분을 입력 후 다시 docker search를 실행 하면 이번에는 정상적으로 검색이 되는걸 볼 수 있습니다.

이렇게 docker search로 검색이 된다면 제가 ubuntu image를 받아서 바로 쓸 수 있던것 처럼 다른 사용자들도 제가 방금 push한 image를 받아서 사용할 수 있습니다.

이번에는 방금 만들었던 xe3:0.1 image를 container로 만들어서 composer를 설치해 보겠습니다. container로 만드는 부분은 기존과 동일하고 위에 적혀있는 명령어를 사용해서 composer를 설치합니다.

설치 후 composer 명령을 실행 했을 때 위와 같이 composer에 대한 정보와 composer 명령어가 출력되는 것을 확인 후 xe3:0.1 image를 만들 때와 마찬가지로 exit 명령으로 container를 빠져 나와서 xe3:0.2로 commit, push를 실행 해서 composer까지 설치된 xe3:0.2 image를 배포합니다.

docker는 image를 저장할 때 layer라는 개념을 사용하는데 이번에는 잠깐 image layer에 대해서 살펴보겠습니다.

지금까지의 과정을 그대로 실행하면 위와 같이 docker images 명령어를 실행 했을 때 ubuntu:latest, xe3:0.1, xe3:0.2 image가 남아 있습니다.

docker inspect 명령어를 실행하면 해당 image의 상세 정보를 볼 수 있습니다.

docker inspect 명령을 실행해서 가장 밑으로 내려가보면 위와 같이 layer라는 항목이 있습니다. 위 그림은 각각 ubuntu:latest, xe3:0.1, xe3:0.2 image의 layer입니다.

자세히 보면 ubuntu:latest가 가진 4개의 layer를 xe3:0.1, xe3:0.2가 동일하게 가지고 있는 것을 볼 수 있습니다.

추가로 xe3:0.1 image는 ubuntu:latest의 4개의 layer 이외에 1개의 layer를 더 가지고 있고 xe3:0.2 image는 xe3:0.1 image의 layer 이외에 1개의 layer를 더 가지고 있습니다.

사용자가 image를 container로 만들어서 실행할 때 기존의 image는 수정이 불가능한 상태이기 때문에 사용자가 container에서 실행하는 모든 작업은 image 이외에 추가로 layer를 만들어서 저장이 됩니다.

간단하게 위 그림을 보면 ubuntu:latest image를 container로 만들어서 php를 설치하고 xe3:0.1 image를 만들었는데 ubuntu:latest image는 수정이 불가능한 상태이기 때문에 php를 설치한 내역은 새로운 image를 추가해서 기록이 되고 ubuntu:latest image는 아무런 변동 사항이 없습니다. 마찬가지로 xe3:0.2 image도 xe3:0.1 image 위에 composer를 설치했지만 역시 xe3:0.1 부분의 image는 수정이 없고 새롭게 추가된 layer에 composer 설치에 대한 내역이 저장됩니다.

이렇게 layer 개념을 사용해서 image를 저장하면 가장 큰 장점으로는 image를 재사용 할 수 있습니다. ubuntu:latest image를 사용해서 아무리 많은 container를 만들고 많은 작업을 했더라도 ubuntu:latest image에는 아무런 변동 사항이 없기 때문에 항상 초기상태를 유지한 image를 사용 할 수 있습니다.

image layer의 특징을 조금 더 살펴보도록 하겠습니다.

특징을 보기 위해 사용 했던 container를 삭제하고 docker rmi 명령을 사용해서 ubuntu:latest image를 삭제하면 Untagged라는 문구를 볼 수 있습니다.

마찬가지로 xe3:0.1 image를 삭제 할 때 도 Untagged라는 문구가 출력되는걸 볼 수 있는데 xe3:0.2 image를 삭제할 때는 Untagged 이외에 Deleted라는 문구를 볼 수 있습니다.

ubuntu:latest, xe3:0.1 image를 삭제할 때 Deleted 대신 Untagged라는 문구가 출력되는건 ubuntu:latest와 xe3:0.1 image가 사용하고 있던 layer에 ubuntu:latest, xe3:0.1이라는 tag를 제거 했을 때 tag가 지정되어 있던 layer를 사용하고 있는 image가 컴퓨터에 남아 있기 때문에 사용하던 layer는 삭제하지 않고 tag만 제거해서 ubuntu:latest와 xe3:0.1 image의 저장 내역을 삭제합니다.

하지만 xe3:0.2 image를 삭제할 때는 xe3:0.2 tag를 제거하면 xe3:0.2가 사용하던 layer들은 더이상 사용하고 있는 다른 image가 없기 때문에 그때 image layer들을 삭제합니다.

모든 image들을 삭제 후 다시 docker pull 명령어를 이용해서 image를 받을 때 xe3:0.2 image를 먼저 받게 되면 모든 layer를 docker hub에서 받아 오는 걸 볼 수 있습니다. 하지만 ubuntu:latest image를 다운로드 받으려고 실행 하면 컴퓨터에는 xe3:0.2를 받으면서 xe3:0.2가 가지고 있는 ubuntu:latest의 layer까지 모두 저장 되어 있는 상태이기 때문에 ubuntu:latest에 대한 layer는 다시 받을 필요가 없습니다. 그래서 ubuntu:latest의 layer에 ubuntu:latest tag만 연결해 주면 다운로드를 받을 필요 없이 ubunt:latest를 사용할 수 있습니다.

이와 같이 docker는 image를 관리할 때 layer를 사용하고 있어서 저장공간과 다운로드하는 시간을 절약할 수 있습니다.

이번에는 기존에 composer까지 설치했던 xe3:0.2 image에 xe3를 다운받아 보겠습니다. 마찬가지로 xe3:0.2 image를 활용해서 conatiner를 만들고 적어둔 명령어를 순서대로 실행해서 git 설치, git clone을 활용해서 xe3 다운로드, composer install을 활용해서 xe3에 필요한 패키지를 설치합니다.

xe3를 정상적으로 다운 받고 마찬가지로 지금까지 설치된 부분을 xe3:0.3 image로 만들어서 docker hub에 업로드를 합니다.

이번에는 xe3:0.3 image에 server를 구동시키기 위한 apache를 설치해 보도록 하겠습니다. 이번에는 기존과 다른게 docker run 명령어에 -p 옵션이 추가되었습니다.

-p 옵션은 host 컴퓨터의 port와 container의 port를 연결해 주는 옵션입니다.

http 접속을 하기 위해서 host 컴퓨터의 80번 port와 container의 80번 port를 지정했습니다. 만약에 host 컴퓨터의 8080 port와 container의 80번 port를 연결 하고 싶다면 -p 8080:80을 지정합니다.

docker run 명령을 실행 후 port가 연결되어 있는 상태를 보기 위해서 container를 빠져 나오는데 기존과 다르게 exit 명령어가 아닌 키보드에 ctrl 키를 누른 후 p와 q를 연속해서 입력합니다.(ctrl+pq) container를 빠져 나온 후 docker ps 명령을 실행해 보면 기본과 다르게 container의 상태가 exited 상태가 아닌 up 상태인 것을 볼 수 있습니다.

ctrl+pq를 입력해서 빠져 나오면 container를 종료시키지 않는 상태에서 빠져 나올 수 있습니다.

다시 docker ps의 결과를 보면 -p 옵션으로 port를 지정했기 때문에 ports 부분에 지정된 port가 연결된 것을 볼 수 있고 docker port 명령을 통해서 port의 정보만 따로 볼 수 있습니다.

port의 상태를 확인하고 다시 container로 접속하기 위해서 docker attach 명령을 사용해서 container로 접속합니다.

이번에는 container에 server로 사용할 apache를 설치 하고 설정을 해 보도록 하겠습니다. 위에 있는 명령어를 그대로 실행 하는데 xe.conf 파일의 내용은 오른쪽에 있는 내용을 그대로 붙여넣기 합니다.

xe.conf 파일은 vi 에디터를 사용해서 만드는 데 vi 에디터의 사용이 어려우신 분들은 인터넷에 검색해보시면 쉽게 설명되어 있는 사이트가 많기 참고하시면 될 것 같습니다.

  • 검색해도 내용이 어려우신 분들은 자료의 xe.conf 파일의 내용을 복사 =>vi xe.conf => i => 붙여넣기 => esc 클릭 => : 입력 => wq 엔터
  • 다른 입력 없이 위에 적은 키를 그대로 입력하시면 xe.conf 파일을 생성할 수 있습니다.

위에 적힌 명령어를 전부 실행 후 웹 브라우저에서 127.0.0.1에 접속해 보면 위와 같이 xe3의 install 페이지에 접속이 가능 합니다.

하지만 아직 database가 없어서 정상적인 설치가 되지 않습니다. database 연결을 실습하기 앞서서 xe3 실행에 필요한 php, composer, xe3, apache가 설치된 container를 xe3:0.4 image로 만들어서 push를 합니다.

이번에는 지금까지 만들었던 xe3:0.4 container와 mysql container를 연결해 보도록 하겠습니다. 간단하게 테스트만을 위한 image를 만드는 과정에서는 xe3 image안에 database를 설치해서 하나의 image 안에서 xe와 database까지 사용 할 수 있지만 그렇게 된다면 해당 image의 수정이 어려워지고 container를 삭제하면 database의 내용까지 전부 삭제가 되기 때문에 mysql container를 만들어서 xe3 container와 연결을 해 보도록 하겠습니다.

mysql을 실행하는 docker run 명령어에 -d 옵션이 추가되었는데 -d 옵션은 mysql이 하나의 terminal을 사용하기 때문에 mysql을 계속 실행 상태로 두기 위해서 -d 옵션을 지정합니다. -d 옵션을 지정하고 docker run을 실행하면 기존과 다르게 docker run 명령이 실행 됐을 때 container에 접속되는게 아니라 생성된 container의 id만 출력되고 container로 접속은 되지 않습니다. 이 때 docker ps 명령으로 container의 상태를 보면 up 상태로 실행이 되고 있는것을 확인 할 수 있습니다.

-e 옵션은 해당 image의 환경변수를 지정할 수 있습니다. MYSQL_ROOT_PASSWORD 환경 변수는 mysql root 계정의 비밀번호를 지정하고 MYSQL_DATABASE 환경 변수는 mysql container가 생성되면서 자동으로 생성할 database의 이름을 지정할 수 있습니다. 이외에도 많은 환경변수가 있는데 환경변수의 목록은 docker hub에서 mysql을 검색해서 mysql repository의 description에서 볼 수 있습니다.

mysql container가 제대로 동작하는지 확인해 보기 위해서 docker exec 명령을 사용해서 mysql container를 실행해 보겠습니다. docker exec 명령은 command로 지정한 명령을 container에 실행하는 명령입니다. docker run과 마찬가지로 terminal을 사용하기 위해 -it 옵션을 지정하고 bash라는 command를 실행해서 terminal로 접속합니다.

mysql container에 접속 후 root 계정으로 접속을 하는데 비밀번호는 container를 생성할 때 환경변수로 지정했던 비밀번호가 지정되어 있습니다. mysql에 접속 후 database의 목록을 보면 마찬가지로 환경변수로 지정했던 이름의 database가 생성되어 있는 것을 확인 할 수 있습니다.

mysql container를 빠져 나와서 이번에는 실행중인 mysql container와 xe3:0.4 image를 사용하는 container를 연결해보도록 하겠습니다. docker run 명령어를 사용해서 xe3:0.4 container를 실행 하는데 이번에는 — link라는 옵션이 추가되었습니다. — link 옵션은 실행중인 다른 container와 생성하는 container의 연결을 지정할 때 사용합니다.

xe_db는 mysql container의 이름이고 mysql image를 사용하기 때문에 — link xe_db:mysql이라는 옵션을 추가해서 container를 생성합니다.

정상적으로 container를 실행 되면 apache를 실행하는 명령어인 service apache2 start를 실행 후 다시 웹 브라우저를 통해서 127.0.0.1에 접속 후 관련 정보를 입력 할 때 database의 주소는 mysql container의 이름인 xe_db를 입력 후 설치를 하면 정상적으로 xe3가 설치되어서 실행하는 모습을 볼 수 있습니다.


지금까지는 ubuntu:latest image 위에 계속해서 필요한 패키지를 추가하면서 새로운 image를 만들어보는 과정을 진행해봤습니다. 하지만 이렇게 image를 만드는 방식에는 몇가지 단점이 있는데 image에 간단한 설명은 남길 수 있지만 구체적인 정보를 남기기 어렵기 때문에 나중에 image를 보면 어떤 패키지가 설치되어 있는지 확인이 어렵고 docker search 명령으로 다른 사용자가 올린 image를 사용하려면 그 image안에 구성이 어떻게 되어 있는지 확인이 어렵기 때문에 완전히 믿고 사용하기 어려운 부분이 있습니다.

Dockerfile을 사용하면 위에 언급한 단점을 해결할 수 있습니다. 그래서 이번에는 위에 xe3 image를 만들었던 과정을 Dockerfile로 만드는 과정을 진행해 보도록 하겠습니다.

Dockerfile은 설치해야 패키지, 명령, 옵션 등을 하나의 파일에 작성해서 작성한 파일을 build해서 image를 생성하기 때문에 해당 image의 상세한 내역을 확인 할 수 있고 Dockerfile만 공유하면 같은 환경을 구축할 수 있기 때문에 공유를 편하게 할 수 있습니다.

Dockerfile을 만들기 전에 xe3 image를 만들 때 사용했던 xe.conf 파일을 미리 만들어 둡니다. Dockerfile을 build 하는 과정에서는 사용자가 입력을 할 수 없기 때문에 입력해야 하는 내용이나 설정 파일 등은 미리 만들어 두고 build 하면서 image에 포함되도록 합니다.

xe.conf 파일과 같은 경로에 위와 같은 내용으로 Dockerfile을 추가합니다.

빨강색으로 색을 넣은 부분은 Dockerfile의 명령어입니다.

먼저 FROM은 xe3 image를 만들었을 때 처음에는 ubuntu:latest의 image를 받아서 그 위에 패키지를 하나씩 설치했던 것 처럼 가장 기초가 되는 image를 지정합니다.

LABEL은 생성될 image의 meta-data를 지정합니다. LABEL로 지정된 data는 docker inspect 명령을 실행 했을 때 출력됩니다.

ENV는 환경변수를 지정합니다. 지금 생성하는 Dockerfile에 지정된 DEBIAN_FRONTEND=noninteractive라는 환경변수는 php가 설치 될 때 timezone 설정을 위해서 사용자의 입력을 받는 부분이 있는데 그 부분을 무시하기 위해서 지정합니다.

RUN 명령은 apt-get update, composer install 등 bash 안에서 입력하는 명령어를 지정하게 되면 Dockerfile이 build 하면서 실행할 명령어를 지정합니다.

WORKDIR 명령어는 다음 명령어가 실행될 directory를 지정합니다. RUN 명령에서 cd 명령어를 통해서 directory를 이동하는 명령을 지정해도 다음 RUN 명령을 실행할 때는 cd로 이동한 directory가 반영되지 않고 root directory로 설정이 됩니다. 그렇기 때문에 directory의 이동이 필요한 경우 꼭 WORKDIR 명령어를 실행해서 directory를 이동해야 합니다.

ADD 명령어는 host 컴퓨터에 있는 파일을 새롭게 build해서 생성하는 image에 파일을 추가할 때 사용합니다. 이번 예제에서는 미리 만들어둔 xe.conf 파일을 지정한 경로에 추가하는데 사용했습니다.

CMD 명령어는 Dockerfile을 build해서 생성된 image를 실행할 때 자동으로 수행할 명령어를 지정합니다. CMD 명령은 Dockerfile에 하나만 지정할 수 있습니다. CMD로 지정된 명령어는 docker run이나 docker start할 때 command로 지정되어 있는 명령어가 있으면 Dockerfile의 CMD는 무시됩니다. ubuntu:latest 같은 경우 Dockerfile CMD에 /bin/bash 라는 명령이 지정되어 있기 때문에 ubuntu:latest가 실행 됐을 때 별다른 command가 지정되지 않으면 자동으로 bash가 실행이 될 수 있고 위에서 docker run 명령어를 처음 설명했을 때 처럼 docker run 명령에 echo hi라는 command를 지정할 경우 ubuntu:latest Dockerfile에 CMD로 지정된 /bin/bash가 무시 되고 docker run에서 지정된 command인 echo hi가 실행이 됐습니다.

이번 예제에서의 Dockerfile의 주의점은 ADD 할 때 xe.conf 파일의 경로를 지정하지 않았기 때문에 Dockerfile과 xe.conf가 같은 경로에 있어야 되고 Dockerfile은 파일 이름을 대소문자로 구분하기 때문에 Dockerfile로 지정해줘야 아래 예제를 정상적으로 실행할 수 있습니다.

Dockerfile을 정상적으로 생성 했다면 docker build 명령어를 통해서 Dockerfile을 build하고 image를 생성할 수 있습니다. -t 옵션은 생성되는 image의 이름과 tag를 지정할 수 있습니다. 마지막 인자로는 docker build를 실행하는 경로에 Dockerfile이 존재하기 때문에 같은 경로라는 의미로 . 을 넣어줍니다.

docker build 명령을 실행하면 Dockerfile에 작성되어 있는 내용으로 자동으로 작성된 내용을 실행해서 image를 생성해 줍니다.

이번에는 작성한 Dockerfile을 수정하면 자동으로 Docker Hub에 수정한 내용을 토대로 build해서 새로운 image를 배포하도록 automated build를 설정해 보겠습니다. Dockerfile을 push하는 repository는 github와 bitbucket를 사용 가능하지만 이번 예시는 github를 사용해 보도록 하겠습니다.

  • Dockerfile을 push할 github repository를 생성합니다.
  • Docker Hub에서 automated build repository를 생성 하는데 github의 계정과 연동이 필요 합니다. 계정 정보를 입력해서 Docker Hub와 github를 연결합니다.
  • 계정의 연동이 되면 해당 github의 repository 목록이 나오는데 Dockerfile을 push할 repository를 선택합니다.
  • Docker Hub의 automated build repository에서 간단한 설명과 설정을 하고 생성 합니다.
  • Docker Hub에서 automated build reposiroty가 생성 되면 작성한 Dockerfile을 github에 push 합니다. (예제에서는 xe.conf 파일도 필요하기 때문에 xe.conf도 같이 push 합니다.)
  • github에 Dockerfile이 push 되면 자동으로 Docker Hub에서 build를 시작합니다.
  • Build Detail 탭에 접속하면 build에 관련된 정보를 볼 수 있습니다. Dockerfile이 push된지 얼마 안됐을 때는 Queued 상태에 있지만 잠시 대기 후 차레가 되면 build 상태로 변경 되고 build가 끝나면 failed나 success 상태로 변경됩니다.
  • success 상태가 되면 docker search 명령을 통해서 해당 Dockerfile을 토대로 만든 image를 다운 받을 수 있습니다.

Dockerfile을 사용해서 xe3 container는 쉽게 만들 수 있지만 여전히 database는 별개의 container에 있기 때문에 항상 mysql container를 먼저 생성하고 xe3 container를 생성하면서 link를 해줘야 하는 복잡하고 귀찮은 문제가 있습니다.

이번에는 그런 문제를 극복하기 위해서 docker-compose를 사용해 보겠습니다. docker-compose는 여러 개의 container를 실행할 때 docker-compose.yml 파일에 관련된 내용을 작성해서 한번에 여러 개의 container를 관리 할 수 있습니다.

먼저 볼 docker-compose.yml 파일은 처음에 만들었던 xe4:0.4 image를 사용해서 xe3를 실행하는 예제입니다.

version에 작성되는 내용은 docker-compose.yml 파일의 버전입니다. 사용 가능한 버전은 docker-compose의 버전을 확인해서 사용 가능한 yml 파일 버전을 확인 할 수 있는데 예제에서는 3.0 버전을 사용합니다.

services에는 docker-compose로 묶어서 한번에 관리할 container의 목록을 작성 합니다. 위의 예제에서의 xe, xe_db로 작성된 내용은 해당 container의 이름입니다.

docker run에서 옵션으로 사용했던 ports, links, command, environment 등 옵션 내용도 container의 이름 밑에 작성합니다.

이번 docker-compose.yml 파일은 Dockerfile을 사용하는 docker-compose.yml 파일입니다. 다른 부분은 기존과 동일하지만 이번에는 xe container에 image가 아니라 build라는 항목이 추가되었습니다. build에서 context라는 항목이 있는데 context에는 Dockerfile이 존재하는 경로를 지정해 줍니다. 예제에서는 Dockerfile과 docker-compose.yml 파일이 같은 경로에 있기 때문에 .을 입력 했습니다. dockerfile 항목에는 Dockerfile의 이름을 지정합니다.

위 docker-compose.yml 예제 중 한가지를 선택해서 docker-compose.yml 파일을 만들고 docker-compose를 실행해 보겠습니다.

docker-compose.yml이 존재하는 경로에 접속해서 docker-compose up 이라는 명령을 통해서 docker-compose.yml에 작성된 내용을 실행합니다. xe와 xe_db 모두 terminal을 사용하는 apache와 mysql이 있기 때문에 -d 옵션을 지정했습니다.

image를 사용하는 경우 해당 image가 없으면 다운로드를 받고 Dockerfile을 사용하는 경우 build가 되어 있지 않으면 자동으로 build를 실행합니다.

docker-compose up이 완료 되면 docker-compose.yml에서 지정한 2개의 container가 생성 된 것을 확인할 수 있습니다.

container의 이름은 해당디렉토리_container이름_conatiner번호로 생성됩니다.

docker-compose로 생성된 container의 상태를 확인하려면 docker-compose ps라는 명령어를 사용합니다. docker ps 명령으로도 확인이 가능하지만 docker ps 명령어는 docker로 실행했던 container까지 출력이 되고 docker-compose ps 명령은 docker-compose로 실행한 container만 출력이 됩니다.

docker-compose로 실행한 container는 종료되면 자동으로 삭제 되기 때문에 docker-compose ps 명령은 -a 옵션이 없습니다.

docker-compose up으로 실행한 container들은 종료 하려면 docker-compose down 명령을 실행 합니다. docker-compose down 명령은 실행중인 container들을 종료 후 삭제합니다.

위와 같이 image 안에 source code까지 포함이 되면 source code 수정이 될 때마다 image을 새로 작성해야 되고 phpstorm 등 ide를 사용해서 source code를 수정 할 수 없기 때문에 버전 테스트용도로는 image 안에 source code가 포함 되는게 괜찮고 편할 수 있지만 개발을 하는 용도로는 불편한 점이 있습니다.

database 같은 경우에도 container를 삭제하면 database 안에 저장되어 있던 data까지 삭제 되기 때문에 계속해서 사용하기 어렵습니다.

그렇기 때문에 개발 환경 공유를 목적으로 사용하려면 source code와 앞서 설치했던 php, composer, apache와 같은 패키지를 분리하고 database의 data 저장 부분을 container에서 분리 하는 작업이 필요합니다.

먼저 source code와 개발에 필요한 패키지가 설치되어 있는 container를 분리해 보도록 하겠습니다.

현재 volume_test:1.1이라는 image안에는 php, apache가 설치 되어 있습니다. host 컴퓨터에는 source code가 저장되어 있는 xpressengine이라는 폴더와 database의 data를 저장할 database 폴더가 있습니다.

먼저 mysql container를 만들어 보겠습니다. docker run 명령어를 사용하는데 -v 옵션을 사용해서 host 컴퓨터의 database 폴더와 container의 /var/lib/mysql 폴더를 연결합니다. -v host path:container path 와 같은 형식으로 입력합니다.

-v 옵션을 지정해서 container를 실행하고 mysql container와 연결한 host path를 접속해보면 docker run 실행 전과 다르게 mysql의 data에 관련된 파일들이 생성된 것을 볼 수 있습니다.

이번에는 php, apache가 설치된 image를 container로 만드는데 host 컴퓨터에 저장된 source code를 사용하도록 -v 옵션을 지정했습니다.

2개의 container를 모두 실행 한 후에 host에서 complete라는 파일을 생성해보고 container에 접속해서 source code 연결을 지정한 path로 이동해서 파일 목록을 보면 host에서 생성한 파일이 container 내부에도 연결되는 것을 확인할 수 있습니다.

이와 같은 환경을 구성하면 다른 사람들과 개발 환경을 공유할 때 source code는 각자 개발중인 source code를 사용하면서 php, apache와 같이 공통적으로 사용하는 개발 환경의 버전이나 설정은 동일하게 공유 할 수 있습니다.

이번에는 방금 host와 container의 연결을 docker-compose.yml에 적용하는 방법입니다. 다른 부분은 기존과 동일하고 volumes 옵션을 통해서 source code의 경로와 database의 data 저장 되는 경로를 추가 할 수 있습니다.