docker-compose의 활용
몇년전부터 docker가 사람들 사이에 오르내리기 시작하다 최근에 많은 곳에서 docker를 사용중에 있고 다양한 오픈소스들 대부분이 docker이미지를 제공하고 있다. 그렇다면 docker를 어디에 활용하면 좋을까? 주로 서비스를 위해 사용되는 경우도 많지만 개발을 할 때 다양한 인프라 플렛폼을 제공해 주는 역활로도 주로 사용될 수 있을것이다.
단순히 docker만 이용해서 여러가지 인프라에 대한 개발환경을 구축할때에는 약간 곤란한 점이 있었다. 예를 들어 elasticsearch에 kibana를 붙이고 여기에 또 mysql과 kafka를 함께 사용한다면 거기에 몇가지 요소들, 만약 hadoop 계열로 테스트 환경을 같이 구축해야 한다면 아무리 docker를 이용한다고 하더라도 각각의 포트와 이미지와의 연결을 하느라 꽤 시간이 걸릴것이다.
그렇다면 이런것을 한번에 해결하고자 한다면 어떻게 하면 될까 ? docker에서는 compose라는 것을 제공한다. compose는 멀티 container docker 어블리케이션을 정의하고 실행하는 툴로서 어플리케이션의 서비스를 YAML 파일에 설정하여 사용할수 있다. 설정된 YAML 파일을 이용하면 단지 하나의 명령어로서 어플리케이션 실행에 필요한 모든 환경 구성을 완료 할수 있다.
Docker Compose는 아래와 같은 기능을 제공한다고 한다.
1. 하나의 시스템에서 여러개의 고립된 환경을 제공
2. Container들이 생성될때 데이터를 보존
3. 변경된 Container들만 재생성 하게 함
4. 변수와 각 환경간의 요소 이동
하나의 PC에서 다수의 환경을 구성해서 분산 환경을 구축하여 개발에 테스트 해볼수도 있으며 설정 이나 데이터등은 별도의 공간이나 호스트에 위치 시킬수도 있다. 구지 docker 이미지에 attach 하지 않는다 하더라도 많은 부분을 세밀하게 설정하고 구축할수 있는 점이 있다.
이제 어디에 활용 할수 있을지 조금은 감을 잡으셨을거라고 생각한다. 이미 Docker를 사용하고 있겠지만 Docker-Compose 하나로 웬만한 오픈소스 개발 인프라의 환경 구축을 끝낼수 있다. 뿐만아니라 만약 직접 Docker 이미지를 만들고 자체 저장소를 이용한다면 기업이나 학교에서 사용되는 플렛폼의 테스트 환경을 간단하게 명령어 하나로 제공이 가능해 질것이다.
이 글에서는 Compose에 대한 사용에 대한 소개와 Compose 공식 메뉴얼에 나와 있는 Python Flask를 이용한 간단한 앱의 Deploy와 개발시에 많이 사용되고 있는 Hbase, ELK, MongoDB, MySQL 등에 대한 Compose 설정을 알아 보고자 한다.
우선 Docker가 설치된 상태에서 Compose에 대한 설치를 진행한다. 자세한 설치에 대한 내용은 아래 링크를 참고하기 바란다.
https://docs.docker.com/compose/install/
리눅스에서는 Github을 통해서 설치를 진행하여야 하며 아래의 명령어를 통해서 다운로드 하여 설치 할수 있다.
sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
맥에서는 Docker 를 설치하였다면 툴로서 이미 포함되어 있으므로 별도로 설치를 할 필요는 없다. 맥에서 도커 설치에 익숙하지 않다면 아래의 링크를 통해서 설치를 진행할 수 있다.
https://docs.docker.com/docker-for-mac/install/
Docker Compose는 일반적으로 사용되는 Docker의 옵션이나 명령어들을 docker-compose.yml 이라는 파일에 저장하고 이를 통해서 한번에 다수의 Docker 인스턴스들을 관리하고 연결할수 있게 해준다. 그럼 compose의 기본적인 문법들에 대해서 알아 보자.
( 지금까지 Compose는 3가지 버전이 나와 있으며 본 글에서는 버전 3을 기준으로 설명하고자 한다.)
https://docs.docker.com/compose/compose-file/
문법에 대해서 세부적으로 알아야 하나 여기서는 필수적으로 필요한 부분만 다룬다.
Compose를 사용하고자 할 경우 Docker의 설정들을 문법에 맞추어서 docker-compose.yml (혹은 yaml) 파일로 생성하면 된다.
build 시에 적용되는 옵션으로 build 하고자 하는 내용들이 포함되어 있는 위치를 지정한다. 하부적으로 context, dockerfile, args 옵션을 사용하여 세부적인 옵션도 줄수 있다. 만약 image 를 적을 경우 이름을 줄수도 있다.
build: ./dir
image: webapp:tag
build시에 별도로 값을 변경 하고자 할때 사용할 수 있다. 만약 Dockerfile에 아래와 같이 되어 있다면
ARG buildno
RUN echo "Build number: $buildno"
docker-compose.yml을 통해서 값을 전달하는것이 가능하다.
build:
context: .
args:
buildno: 1
% 문법 추가 정리중
사용하지 않는 이미지들 삭제 명령어
사용법
docker system prune [OPTIONS]
EX.) docker system prune -a -f ( 사용하지 않는 모든 이미지들을 별도의 Y/N 문의 없이 삭제 한다.)
https://docs.docker.com/compose/gettingstarted/
Docker Compose를 이용하여 간단하게 redis와 Python Flask를 이용한 서비스를 구현한 예제를 소개한다. 개략적으로 서비스에 어떻게 Compose를 이용하여 Deploy 할수 있는지를 알수 있다.
여기서는 요약한 내용만 간략하게 전달하고자 한다.
먼저 본인이 개발하고자 하는 어플리케이션을 개발하고 이를 Dockerfile을 통해서 Docker 이미지를 만들어야 한다. 그러기 위해서 아래의 간단한 app.py 파일을 작성한다.
app.py
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
위의 예제에서 주의해서 볼 만한 부분은 redis에 연결하기 위해서 사용되는 host 이름에 docker-compose에서 사용되는 이름이 들어가 있다. docker-compose에서 작업 하면서 자주 볼수 있는 부분으로 compose내에서 작성된 이름을 호스트 이름으로 접근 할수 있게 된다.
이제 파이선 필수 요소를 설치하기 위해서 requirements.txt 파일을 만들고 아래 내용을 입력한다.
requirements.txt
flask
redis
위의 두가지 파일을 만드는 것만으로 간단하게 웹상에서 redis를 이용하여 접속을 몇번 했는지에 대한 카운터의 작성이 완료 되었다.
이제는 위에서 만든 앱을 Docker 이미지로 만들어야 한다. 도커 이미지는 파이선 3.4로 작성된 기본 Docker 이미지에 코드를 입력하는 형식으로 구성해 본다. 아래의 내용을 Dockerfile 이라는 이름으로 위의 app.py와 requirements.txt가 있는 동일한 폴더에 넣는다.
Dockerfile
FROM python:3.4-alpine
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
위의 파일을 입력하는것 만으로 충분하다. 해당 파일에 대한 추가적인 설명은 세번째 과정에서 하겠다. 추가적으로 본인이 만든 어플리케이션을 배포하기 편리하게 docker 이미지로 구성하고자 하는 경우 아래의 레퍼런스를 참고 하기 바란다.
https://docs.docker.com/engine/reference/builder/
이제 앱을 개발하고 이를 Docker 이미지로 구성했다. 최종적으로 docker-compose.yml파일을 작성하여서 redis와 개발한 앱을 같이 배포해 보자.. 우선은 아래의 docker-compose.yml 파일을 만들자.
docker-compose.yml
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
redis:
image:"redis:alpine"
간단하게 web과 redis 두가지 이미지를 사용하게 된다. web의 경우에는 build 옵션을 주어서 현재 디렉터리에 Dockerfile을 통해서 빌드를 하고 이미지내의 5000번 포트를 외부로 5000번으로 맵핑하도록 해 주었다. redis는 배포되고 있는것을 사용한다.
그럼 docker-compose up명령어를 통해서 실제로 이미지를 빌드하고 redis를 deploy 해보자.
$ docker-compose up
Creating network "composetest_default" with the default driver
Building web
Step 1/5 : FROM python:3.4-alpine
3.4-alpine: Pulling from library/python
6c40cc604d8e: Pull complete
eb28c72fd5c9: Pull complete
21863ada74e5: Pull complete
476baf747d43: Pull complete
86cd756eb1c0: Pull complete
Digest: sha256:89f91424749e3758400eb4f759554db4b0e548d234d74f49c66fd9674d4ff4b3
Status: Downloaded newer image for python:3.4-alpine
---> 312d01c5d97d
Step 2/5 : ADD . /code
---> 0afad6719e6b
Step 3/5 : WORKDIR /code
---> Running in f08e582fa9d5
Removing intermediate container f08e582fa9d5
---> 5f71f2c9d833
Step 4/5 : RUN pip install -r requirements.txt
---> Running in b1793e05549c
DEPRECATION: Python 3.4 support has been deprecated. pip 19.1 will be the last one supporting it. Please upgrade your Python as Python 3.4 won't be maintained after March 2019 (cf PEP 429).
Collecting flask (from -r requirements.txt (line 1))
여러가지 에러 메시지가 나오면서 아래와 같이 최종적으로 두개의 이미지가 잘 올라간것을 알수 있다.
redis는 6379 포트를 도커 내부에서만 오픈하고 있다. 이는 docker-compose에 정의된 이미지들 끼리는 통신이 가능하며 위에서 개발한 앱으로 만든 app.py는 5000번 포트를 외부로 오픈했으므로 접근이 가능하다. 그럼 한번 http://localhost:5000 으로 접속해 보자.
잘뜨는것을 볼수 있을것이다. 페이지를 리플레시 할때마다 숫자가 1씩 올라가는것을 알수 있다.
기본적으로 위의 과정을 통해서 docker가 동작중인 환경이라면 OS에 상관없이 본인이 개발한 응용프로그램을 서비스 할수 있는 모든 준비가 끝났다. 물론 간단하지만 가장 기본적인 부분을 잘 볼수 있을 것이고 응용한다면 얼마든지 더 복잡한 것을 만들수 있다.
% 하단에 있는 git에 있는 docker-compose 파일을 실행할때 메모리가 충분한 시스템에서 하기를 권장한다. 만약 ElasticSearch 같은 경우 표기된 메모리보다 부족한 경우 Swap이 발생하고 이럴 경우 정상적으로 실행이 되지 않는다.
아래는 개발에 많이 사용되지만 간단한 테스트를 위해서 별도로 구축하기에는 오래걸리거나 Docker들의 Docker-compose 들을 수록하였다. github 링크가 있는 경우 링크를 clone 하여 사용하기 바란다.
MariaDB를 이용하며 관리툴 설치됨, 관리툴이 불필요한 경우 아래의 adminer를 제거
version: '3'
services:
mdb:
image: mariadb
command: --default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
restart: always
environment:
MYSQL_ROOT_PASSWORD: sokobanpass
ports:
- 3306:3306
volumes:
- /Users/sokoban/mysql:/var/lib/mysql
adminer:
image: adminer
restart: always
ports:
- 8080:8080
위의 내용을 docker-compose.yml 파일로 만든 이후 간단하게 #docker-compose up 을 실행하면 자동으로 image 이름이 mariadb와 adminer 두가지 도커 이미지를 다운 로드 한 이후에 자동으로 mysql과 관리툴인 adminer 두가지를 실행 하게 된다. 그러면 http://127.0.0.1:8080을 통해서 자기 자신의 IP주소(127.0.0.1이 아닌 할당된 IP주소)와 입력한 패스워드를 통해서 접속이 가능해 진다.
실제로 사용하고자 한다면 MYSQL_ROOT_PASSWORD의 sokobanpass 부분을 원하는 패스워드로 변경하면 root 접속시 사용할수 있게 된다. 조금 중요하게 생각할 부분은 volumes로서 docker 이미지가 지워지거나 손상되더라도 데이터는 소실되지 않게 하기 위해서 mysql 데이터 부분을 호스트의 디스크 공간으로 맵핑해 주었다.
version: '3'
services:
redis:
container_name: redis
image: "redis:alpine"
ports:
- "6379:6379"
volumes:
- ../data/redis:/data
entrypoint: redis-server --appendonly yes
restart: always
redis-commander:
hostname: redis-commander
image: rediscommander/redis-commander:latest
restart: always
environment:
- REDIS_HOSTS=local:redis:6379
ports:
- "8081:8081"
https://github.com/big-data-europe/docker-hadoop
Hive, HBase 그외에 최근에 인기있는 다양한 NoSQL혹은 오픈소스 엔진이 하둡을 기반으로 한다. 물론 이외에 다양한 오픈소스 솔루션들도 HDFS에 의존하는 경우를 많이 볼수 있다. 테스트라도 한번 할려고 하면 복잡한 하둡을 설치 해야 한다. (요즘은 yum으로 쉽게 설치가 가능하지만 그래도 이것저것 신경 쓸게 많다.)
https://github.com/big-data-europe/docker-hbase
https://linuxsimba.com/developing_with_mongodb
대중적으로 많이 사용하고 있는 NoSQL인 MongoDB와 MongoDB 관리툴을 함께 설치하여 사용할수 있게 해준다.
version: '2'
services:
mongodb:
image: mongo:latest
container_name: mongodb
hostname: mongodb
networks:
- mongodb_net
ports:
- 27017:27017
mongoclient:
image: mongoclient/mongoclient:latest
container_name: mongoclient
hostname: mongoclient
depends_on:
- mongodb
networks:
- mongodb_net
ports:
- 3300:3000
networks:
mongodb_net:
driver: bridge
ipam:
driver: default
config:
# Change this subnet range if it conflicts with your personal/work network
- subnet: 192.168.213.0/24
gateway: 192.168.213.1
설치한 이후에 http://localhost:3300 으로 접근하면 아래와 같이 접속이 가능하다.
Spark
https://github.com/gettyimages/docker-spark
한번에 바로 ELK 환경을 구현하여 바로 테스트 해볼수 있다. 신경 써야 하는 부분은 개별 설정 파일들은 따로 설정해 주어야 하고 Logstash의 경우도 별도로 설정이 필요하다.
version: '2'
services:
elasticsearch:
build:
context: elasticsearch/
args:
ELK_VERSION: $ELK_VERSION
volumes:
- ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro
ports:
- "9200:9200"
- "9300:9300"
environment:
ES_JAVA_OPTS: "-Xmx256m -Xms256m"
networks:
- elk
logstash:
build:
context: logstash/
args:
ELK_VERSION: $ELK_VERSION
volumes:
- ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml:ro
- ./logstash/pipeline:/usr/share/logstash/pipeline:ro
ports:
- "5000:5000"
- "9600:9600"
environment:
LS_JAVA_OPTS: "-Xmx256m -Xms256m"
networks:
- elk
depends_on:
- elasticsearch
kibana:
build:
context: kibana/
args:
ELK_VERSION: $ELK_VERSION
volumes:
- ./kibana/config/:/usr/share/kibana/config:ro
ports:
- "5601:5601"
networks:
- elk
depends_on:
- elasticsearch
networks:
elk:
driver: bridge
https://github.com/deviantony/docker-elk
단지 간단한 설치만으로도 아래와 같이 바로 사용이 가능한 환경이 구축 완료 되었다.
위의 ELK 환경의 경우 일반적으로 분산 환경이 아닌 관계로 그리고 단일 서버상의 메모리 한계로 인해서 초당 수백~수천건의 로그가 들어갈 경우 거의 동작을 멈추는 경우가 많다. 그럴때에는 아래의 분산환경 기반의 ElasticSaech Docker 이미지를 이용하길 바란다. (다만 다운 받은 이후 적절하게 메모리 옵션과 파일 옵션등을 해주어야 한다.)
https://github.com/maxyermayank/docker-compose-elasticsearch-kibana.git
간단하게 최신 버전의 ES만 필요한 경우 ElasticSearch 7.5.1 과 Kibana, Logstash 등을 포함한 버전은 아래의 git에 올려 두었다.
https://github.com/sokoban/dockerdevEnv/tree/master/elastic-kibana-logstash
https://jupiny.com/2016/11/13/conrtrol-container-startup-order-in-compose/
우선 이글은 Docker에 대해서 알아보는 부분은 본인에게 맡기고자 한다. Docker에 대해서 지식이 부족한 분은 아래 글을 참고하기 바란다.
https://blog.nacyot.com/articles/2014-01-27-easy-deploy-with-docker/
docker-compose
https://docs.docker.com/compose/overview/
http://raccoonyy.github.io/docker-usages-for-dev-environment-setup/
http://asuraiv.blogspot.com/2017/07/elasticsearch-docker-compose-elk.html
https://github.com/sokoban/ctia
https://github.com/CarlitosDroid/docker-compose-nodejs-mysql
https://medium.com/@chrischuck35/how-to-create-a-mysql-instance-with-docker-compose-1598f3cc1bee
http://avilos.codes/infra-management/virtualization-platform/docker/docker-compose/
https://github.com/mybb/docker-compose/blob/master/docker-compose.yml.mariadb.example
container_name: redis-commander