Docker 를 이용해서 인스턴스를 생성하고 웹 서버를 구동해 주세요
만약 신입사원인 당신에게 퇴근 전에 갑자기 이렇게 퀘스트가 주어지면 어떨까요?
Docker 를 다뤄 보기는커녕 무엇인지조차 모르는데 말이죠!
'내일 출근인데 어떡하지 😱' 라는 생각에 우선 걱정이 앞설 테고
어떤 자료를 찾아보고 공부해야 할지 막막하지 않을까요?
'내출어' 시리즈는 이 글을 읽는 분들이 이러한 상황에 처했다고 가정했을 때
오늘 밤, 하나의 주제에 대해 한 편의 글을 읽고 나면 내일의 출근이 더 이상 막막하지 않도록
간략한 기초 이론/개념과 팁을 드리는 것이 목표입니다! 🙌
기존의 도커 메뉴얼과 포스팅이 많아서 제 글에서는 어떻게 차별화할까 고민하다가
도커 입문 강의와 현업에서 배운 내용들을 모두 한번에 정리했습니다.
(도커 입문 강의는 2023년 4월에 진행된 '원티드 프리온보딩 백엔드 코스' 입니다.)
컨테이너화 된 애플리케이션을 배포, 관리 및 실행하기 위한 오픈소스 플랫폼
https://docs.docker.com/get-started/overview/
이 도커 파일을 빌드하면 도커 이미지
가 생성됩니다.
또는 도커 파일을 따로 만들고 빌드하는 대신 Docker Hub
에서 미리 만들어진 이미지를 다운로드하여 이용할 수 있습니다.
이 도커 이미지를 실행하면 도커 컨테이너
가 생성됩니다.
Docker에서 공식적으로 제공해주는 이미지가 있으며 사용자는 해당 이미지 혹은 다른 개발자들이 만들어 놓은 이미지를 사용하여 본인만의 커스텀 이미지를 만들 수 있습니다.
도커 레지스트리에는 이미지를 만들어 push할 수 있으며 push된 이미지는 다른 사람들과 공유할 수 있습니다.
(저는 GitHub 와 유사하다고 이해했습니다. 오픈소스를 GitHub 에 올려 두면 직접 모든 코드를 작성하지 않고 git clone 으로 내려받기만 해도 즉시 필요한 코드와 기능을 이용할 수 있으니까요!)
도커 이미지가 컨테이너로 생성되고 실행될 때의 라이프 사이클입니다.
https://techmormo.com/posts/docker-made-easy-3-container-lifecycle/
우리는 당장 내일 출근해야 하므로 😂
컨테이너를 실행하기 위해 필요한 명령어 중 run
만 빠르게 훑어보시는 것을 추천드리고요,
docker run
명령어 사용 예시 및 옵션은 이어지는 4. Practice! 섹션에서 소개합니다.
Docker 에 'Airflow' 웹서버를 올리고 구동하는 실습을 해 보겠습니다.
실습에 필요한 주요 Docker 명령어도 함께 소개합니다.
(명령어 소개에 🐳 이모지를 달아서 눈에 잘 띄도록 했습니다.)
(💡Tip) Airflow 는 python 을 이용해서 workflow 를 작성하고 스케줄링, 모니터링을 할 수 있는 플랫폼입니다.
본 실습에서는 Docker File 을 작성하고 빌드하여 Docker Image 를 만들지 않고
대표적인 도커 레지스트리 사이트인 Docker Hub
에서 이미지를 pull 받아 컨테이너 인스턴스를 생성하는 방법과
Airflow 공식 문서에서 Docker-compose.yaml 파일을 다운로드하여 컨테이너 인스턴스를 생성하는 방법 2가지를 소개합니다.
Docker 는 GUI 를 지원하지만 실전에서는 리눅스 서버에서 CLI 로 작업하는 경우가 많을 것입니다.
Docker 홈페이지에서 CLI 설치방법을 소개하고 있으니 따라해 보시고
https://docs.docker.com/engine/install/ubuntu/
영어로 쓰여 있어서 따라하기 어렵거나 이 글을 따라해도 설치가 잘 되지 않는다면
많은 블로그에서 docker 설치 방법을 소개하고 있으니 구글링해보세요 😉
🐳 Docker Install (Ubuntu OS)
# get-docker.sh 다운로드
$ curl -fsSL https://get.docker.com -o get-docker.sh
# ll 명령어로 현재 디렉토리에 get-docker.sh 파일 확인
$ ll
# get-docker.sh 실행하여 Dokcer 설치
$ sh get-docker.sh
Airflow 공식 문서를 참고하여 도커 이미지를 생성하고 빌드합니다.
https://airflow.apache.org/docs/docker-stack/build.html
Airflow 이미지를 만들고 빌드하기 위해서는
먼저 Dockerfile 을 만들고 아래 내용을 복사해서 붙여넣습니다.
Dockerfile
FROM apache/airflow:2.6.1
USER root
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
vim \
&& apt-get autoremove -yqq --purge \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
USER airflow
이미지를 직접 만들지 않고 apache 에서 제공하는 이미지를 이용하고 싶다면
Docker Hub 에서 미리 만들어진 이미지를 내려받아 이용할 수 있습니다.
아래 캡쳐는 Docker Hub 홈페이지에 있는 Airflow 공식 이미지 예제이며,
docker pull apache/airflow
명령어를 이용해 이미지를 내려받을 수 있습니다.
🐳 Docker pull
docker pull apache/airflow
Dockerfile 을 빌드하여 이미지 파일을 생성합니다.
🐳 이미지 생성 (Docker file build)
# = 현재 디렉토리에서 Dockerfile을 읽어 도커 이미지를 만들고,
# 해당 이미지에 airflow 라는 tag 를 붙여라
docker build -t airflow .
이미지가 잘 생성되었거나 다운로드되었는지 확인해 볼까요?
🐳 생성 혹은 다운로드된 이미지 리스트 출력
docker images
사실 도커 명령어는 다음과 같이 각각 따로 존재하지만
docker create
: 컨테이너 생성docker start
: 컨테이너 실행docker pull
: 도커 이미지 내려받기 (pull)일반적으로 이 기능들을 한꺼번에 수행할 수 있는 docker run
을 사용합니다.
아래와 같은 명령어를 입력할 시 로컬에서 해당 이미지를 먼저 찾아본 후 없다면 자동으로 Docker 저장소인 DockerHub에서 해당 이미지를 찾습니다.
그 후 곧바로 해당 이미지를 불러와 컨테이너를 실행합니다.
🐳 Docker run
# 기본 명령어
docker run airflow
docker run 명령어와 함께 사용하는 몇 가지 옵션을 소개합니다.
--name <name>
: 컨테이너 이름 지정
지정하지 않으면 도커가 랜덤한 단어-단어 조합으로 컨테이너 이름을 지정해 줍니다.
-d
: 컨테이너를 백그라운드에서 실행
많은 경우 컨테이너를 백그라운드에서 실행해야 하는데요,
-d 옵션을 사용하면 컨테이너가 detached 모드에서 실행되며, 실행 결과로 컨테이너 ID만 출력합니다.
옵션 없이 실행했다면 해당 터미널에서 Ctrl + C를 눌러서 빠져나오는 순간 해당 컨테이너는 종료될 것입니다.
실제 Production 환경에서 실행될 컨테이너는 대부분 백그라운드 프로세스로 실행됩니다.
-p
: 포트 포워딩
포트를 매핑함으로써 Docker 컨테이너 내에서 실행되는 서비스에 호스트 머신에서 지정한 호스트 포트를 사용하여 접근할 수 있습니다.
# docker run -\
-name <name> \
-p <host_port(=포트포워딩할 포트)>:<container_port(=Airflow 기본 포트)> \
-d apache/airflow
# 호스트 머신의 포트 8000 을 컨테이너 내부의 포트 8080 과 연결
# = 호스트 머신의 포트 8000으로 전송된 모든 트래픽은 컨테이너 내부의 포트 8080으로 전달
docker run --name airflow -d -p 8000:8080 apache/airflow
-rm
: 컨테이너가 종료될 때 컨테이너와 관련된 리소스(파일 시스템, 볼륨)까지 제거
컨테이너를 일회성으로 실행할 때 주로 사용합니다.
-it
: 실행중인 컨테이너에 쉘(shell) 접속
-i
: 컨테이너의 표준 입출력을 사용하겠다는 의미입니다.-t
: 컨테이너의 pseudo tty(가상 터미널)를 통해 접속하겠다는 의미입니다.-i
옵션과 -t
옵션은 같이 쓰이는 경우가 매우 많은데요,
위의 두 옵션을 추가하여 실행중인 컨테이너의 쉘(Shell)에 접근하여 연속으로 명령어를 입력할 수 있습니다.
(= 컨테이너를 종료하지 않고 터미널의 입력을 계속해서 컨테이너로 전달)
-it
옵션은 이렇게 docker run 명령어와 함께 사용할 수도 있고
# airflow 이미지 다운로드 후 설치까지 한번에
docker run --rm -it apache/airflow /bin/bash
docker exec 명령어와 함께 사용할 수도 있습니다.
🐳 실행중인 컨테이너에 쉘(shell) 접속
docker exec -it 'container name' /bin/bash
Docker 컨테이너(container)에 쓰여진 데이터는 기본적으로 컨테이너가 삭제될 때 함께 사라지게 됩니다.
Docker에서 돌아가는 많은 애플리케이션들은 컨테이너의 생명 주기와 관계없이 데이터를 영속적으로 저장을 해야 할 뿐만 아니라 많은 경우 여러 개의 Docker 컨테이너가 하나의 저장 공간을 공유해서 데이터를 읽거나 써야 합니다.
이렇게 Docker 컨테이너의 생명 주기와 관계없이 데이터를 영속적으로 저장할 수 있도록 Docker는 두가지 옵션을 제공하는데요.
첫번째는 Docker 볼륨(volume),
두번째는 바인드 마운트(bind mount)입니다.
이 중 첫번째인 docker 볼륨을 이용하는 옵션은 `-v 입니다.
-v
: 도커 볼륨 마운트Airflow 웹서버도 DB도 컨테이너에서 잘 실행되고 있는데, DB 에 연결이 되지 않는다면!?
Docker 컨테이너(container)는 격리된 환경에서 돌아가기 때문에 기본적으로 다른 컨테이너와의 통신이 불가능하지만 여러 개의 컨테이너를 하나의 Docker 네트워크(network)에 연결시키면 서로 통신이 가능해집니다.
-network
: 컨테이너가 사용할 네트워크 지정
🐳 Docker 네트워크 목록 조회
docker network ls
최종적으로 이 모든 옵션을 조합한 docker run
입니다.
🐳 Docker run
docker run —rm -it -v <host:container_dir> -p <host_port:container_port> —network <network_name> -d apache/airflow
Airflow 인스턴스가 정상적으로 생성되고 실행되는지 확인해 볼까요?
🐳 컨테이너 출력
# 실행중인 컨테이너 리스트를 출력
docker ps
# 실행이 종료된 것을 포함하여 모든 컨테이너 리스트를 출력
docker ps -a
Airfow 인스턴스가 정상적으로 실행되면 총 4개의 컨테이너가 생성되고 서비스가 실행되어야 하는데
4개 중 airflow-webserver 만 정상적으로 실행되었어요.
정상적으로 실행되고 있지 않거나 재설치가 필요하다면 컨테이너와 이미지를 모두 삭제해 봅니다.
🐳 컨테이너, 이미지 삭제
# 모든 컨테이너를 삭제
docker rm $(docker ps -a -q)
# 모든 이미지를 삭제
docker rmi $(docker images -q)
다른 방법을 찾다가 공식문서의 'Running Airflow in Docker' 에서는
이미지를 다운로드하는 방법 대신 docker compose
를 이용하는 방법을 소개하고 있기에 따라해 보았습니다.
Airflow 는 공식 문서에서 docker-compose.yaml 파일과 설명을 제공하고 있습니다.
(파일) https://airflow.apache.org/docs/apache-airflow/2.6.1/docker-compose.yaml
(설명) https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html
docker-compose.yaml 파일을 직접 다운로드하여 docker 가 설치된 리눅스 서버로 옮기거나
서버에서 curl 를 이용해 다운로드합니다.
🐳 Download Docker Compose File
curl -LfO 'https://airflow.apache.org/docs/apache-airflow/2.6.1/docker-compose.yaml'
docker-compose.yaml 을 열어 설정값을 확인하고
우리가 사용해야 할 조건과 환경에 맞게 값을 수정합니다.
예를 들어 이미 사용중인 DB에 연결해야 할 경우
docker-compose.yaml 파일을 수정하여 Airflow 웹서버에 DB를 연결해 줍니다.
DB는 리눅스 서버의 로컬에 설치하여 이용할 수도 있고,
Airflow 를 구동하는 것과 마찬가지로 컨테이너를 이용할 수도 있습니다.
Airflow 는 최초로 실행하기 전에 간단한 환경설정이 필요한데요,
다음과 같이 컨테이너와 마운팅될 디렉토리를 생성해 주고
mkdir -p ./dags ./logs ./plugins
호스트, 컨테이너 파일 권한도 설정해 줍니다.
echo -e "AIRFLOW_UID=$(id -u)\nAIRFLOW_GID=0" > .env
환경설정을 적용하기 위해 DB를 초기화하고 로그인 계정을 생성합니다.
🐳 DB 초기화 & 계정 생성
docker-compose up airflow-init
초기화가 정상적으로 실행되면 다음과 같은 결과를 볼 수 있습니다.
airflow-init_1 | Upgrades done
airflow-init_1 | Admin user airflow created
airflow-init_1 | 2.1.3
start_airflow-init_1 exited with code 0
이제 Airflow 를 실행하여 서비스를 시작합니다!
🐳 Airflow 실행
docker-compose up -d # -d: 백그라운드 실행
Airflow 컨테이너가 정상적으로 실행되는지 확인해 볼까요?
🐳 컨테이너 출력
# 실행중인 컨테이너 리스트를 출력
docker ps
# 실행이 종료된 것을 포함하여 모든 컨테이너 리스트를 출력
docker ps -a
다음과 같이 4개의 컨테이너가 생성되어 서비스가 정상적으로 실행되고 있습니다 🙌
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
98b105a77dff airflow-airflow-triggerer "/usr/bin/dumb-init …" 5 days ago Up 5 days (healthy) 8080/tcp airflow-airflow-triggerer-1
c096fedcb8a5 airflow-airflow-webserver "/usr/bin/dumb-init …" 5 days ago Up 5 days (healthy) 0.0.0.0:8088->8080/tcp,
:::8088->8080/tcp airflow-airflow-webserver-1
afa3b087e76a airflow-airflow-worker "/usr/bin/dumb-init …" 5 days ago Up 5 days (healthy) 8080/tcp airflow-airflow-worker-1
8f52396a2618 airflow-airflow-scheduler "/usr/bin/dumb-init …" 5 days ago Up 5 days (healthy) 8080/tcp airflow-airflow-scheduler-1
Docker : 나만의 도커 이미지 만들기 부터, 클라우드 배포까지!
https://github.com/drum-grammer/docker-pro-wanted
Docker 학습하기
https://wikidocs.net/book/7507
Docker 네트워크 사용법
https://www.daleseo.com/docker-networks/
[Docker] 도커 컨테이너 - 라이프사이클 및 명령어
https://seosh817.tistory.com/353
Running Airflow in Docker
https://wooiljeong.github.io/server/docker-airflow/
그림과 실습으로 배우는 도커 & 쿠버네티스
(시중에 나온 도커 그림책(?) 중 가장 그림이 많고 예뻐서 가벼운 입문용으로 추천합니다.)
http://www.yes24.com/Product/Goods/108431011
https://velog.io/@jiyeong/그림과-실습으로-배우는-도커쿠버네티스
https://ugong2san.tistory.com/4202