도커, 컨테이너 빌드업!

도커, 컨테이너 빌드업!

최적의 컨테이너 서비스를 위한 도커 활용법

저자: 이현룡

추천:

쪽수: 384

발행일:

독서 기간: ~ (65일)

카테고리: 국내도서, IT모바일, 네트워크/해킹/보안, 네트워크일반, OS/데이터베이스, 클라우드/빅데이터, 컴퓨터공학, 소프트웨어공학

yes24로 책 보러가기

42서울 5서클 과제 중 하나인 Inception을 위해서 이 책을 읽기 시작했다.
이것말고도 그림으로 이해하는~ 책을 읽고 싶었지만 전자도서관에서 누군가 대출하고 있어서 이걸 선택했다.

IT산업에서 자주 쓰이는 키워드들을 따로 설명없이 사용하고 있어서 IT 초보자입장에서는 난이도가 있는 책일지도 모르겠다.
예) 고가용성, IaaS, 프로비저닝, 메인 프레임 등 일부는 각주로 달려있거나 뒤에서 설명해주신다.

1장#

1장은 도커와 관련있는 내용들을 설명한다. 인프라쪽에서 왜 도커라는 기술이 필요해졌고 데브옵스로 인해 서비스 개발의 더 집중할 수 있게되었다는 배경을 설명한다.
또한 도커의 발전 과정을 알려주기 때문에 LXC부터 libcontainer OC를 거쳐서 runC OCI까지 도커 내부 기술어떤 식으로 바뀌어 왔는지도 간략하게 알 수 있다.

2장#

나는 M1 + Ventura 13.4.1 환경에서 진행했다. 가상머신 프로그램으로는 UTM을 사용했고 Linux OS는 ubuntu-22.04.1-live-server-arm64를 사용했다.

책에서 하라는 대로 하면 docker가 제대로 설치되지 않는다. arm64라 그런 것 같다. ubuntu 버전이 20.04 이상이라 그런 것 같다.
sudo apt-get -y install docker-ce 대신 sudo snap install docker

그리고 snap으로 설치해서 그런지 sudo systemctl restart docker, sudo systemctl status docker 를 확인할 수 없었다.
또한 sudo usermod -aG docker $(whoami)도 되지 않았다.
이대로 포기해야 하나 싶었지만 구글링을 통해 해결할 수 있었다.
자세한 설명은 Snap으로 docker 설치 하기 Ubuntu 20.04을 참고하길 바란다. 이 과정을 수행하면 내 환경에서 도커를 사용할 수 있게 된다.

근데 과정을 따라하다가 ssh로 가상머신 OS 접근해서 한 화면에 iTerm(4):전자책(6) 비율로 나눠서 보고 싶은 마음이 들었다.

UTM에 ssh 연결 방법

  1. sudo apt-get install net-tools를 통해 ifconfig를 설치
  2. ifconfig 명령어를 수행하고 나온 출력문 중에 나온 IP 주소(내 경우 enp0s1)를 확인
  3. ssh {사용자명}@{IP} -p22로 접속한 뒤 비밀번호를 입력하고 연결

3장#

도커 이미지 세부 정보 조회 파트에서 도커 명령어 활용 중 관리자 권한으로 변경하고 /var/lib/docker 경로에 들어가는 부분이 있다.
snap으로 설치했기 때문에 나는 /var/snap/docker/common/var-lib-docker 이 경로로 들어가야 했다.

도커 로그인 및 로그아웃 파트에서 cat ~ /.docker/config.json을 확인하는 부분도 다르기 때문에 나는 cat ./snap/docker/2895/.docker/config.json 이 경로로 확인했다.

웹에서 접속해서 Access Token을 발급받아야 하기 때문에 복사 붙여넣기가 편하게 SSH 접속을 해서 하길 권장한다.

도커 이미지를 파일로 관리 파트에서 사용하고 있던 컴퓨터가 M1이라 arm64 환경이라 mysql5.7을 다운로드 할 수 없었다. 지금 예제에선 mysql을 실행하진 않으니 문제가 생길까 걱정하지 않아도 괜찮다. docker pull arm64v8/mysqldocker pull mysql 둘 중 아무거나 내려받으면 된다.

도커 컨테이너 명령어들을 배운다. build, image, login, push, pull, commit, run, create, exec, attach, export, import, container, inspect, ps, logs, top, stats, stop, pause, unpause, restart, kill, rm이 주요 쓰이는 것들 같다.

컨테이너를 제어하기 위한 명령어들인 create, start 명령어를 차례로 쓰는 것과 run 명령어는 비슷한 효과를 볼 수 있다.

위에서 mysql 5.7 버전이 깔리지 않는다 했지만 이렇게 하면 받을 수 있다. docker pull --platform linux/amd64 mysql:5.7 실습 3-1을 위해선 5.7로 하는 것이 쉬운 것 같다. 실행이 되지 않는다...
cAdvisor도 M1에서는 지원하지 않는 것 같다.

볼륨에 대한 처리를 할 때 도커 컨테이너가 어떤 것이냐에 따라 활용되는 특정 경로에다가 docker cp를 통해 소스를 전달하는 방법보다, 호스트 경로에 있는 폴더를 볼륨에 연결해서 작업하는 방법이 더 낫다.

볼륨 지정은 잘못된 이름이나 경로여도 폴더를 만들어내기 때문에 오타에 주의해야 할 것 같다. 예시를 그대로 따라하다보면 저자의 /home/hylee 경로가 그대로 노출되는 부분이 있는데 내 경로로 바꿔야 예상치 못한 결과를 피할 수 있을 것이다(실제로 그대로 해보진 않아서 안되는지는 모르겠다).

내가 도커를 어렵다고 느끼는 이유에는 도커의 구조, 명령어, 컨테이너 생명 주기(호스트와 연결되지 않은 데이터의 휘발성), 볼륨 연결, 실제로 어떻게 도커를 활용하는지를 잘 알지 못해서 부담을 느끼는 것 같다.

볼륨을 호스트에서 만들어야 할 경우도 있거나 특정 폴더를 지정해서 쓰는 방식이 있을 수 있다. 아직 도커 볼륨을 실무에서 사용되는 모범 사례를 모르기 때문에 이미 만들어진 볼륨이나 폴더를 확인해서 만들지 말지도 확인해야 하지 않을까 싶다.

도커는 격리된 환경을 제공하기 때문에 자원도 할당하기 편하다. 특정 애플리케이션에서 요구되는 권장 사항까지만 자원을 사용하게 두는 것이 일반적인지 궁금해졌다. 대부분의 도커는 클라우드에서 올라갈텐데 자원을 많이 쓰지 않아야 청구 요금을 줄일 수 있는데 클라우드 제공하는 컴퓨터 자원을 설정하니깐 굳이 하지 않는지 아니면 도커에서도 용량을 제한하는 옵션을 같이 쓰는지 알아봐야 할 것 같다.

4장#

이제 Dockerfile을 사용한다. IaC에 대한 개념도 알려준다.
Dockerfile로 Docker Image를 Build한 뒤, Docker Container를 Run한다.

자주 사용되는 Dockefile 명령어#

FROM

  • 생성하려는 이미지의 베이스 이미지를 지정하는 것. 이미지 태그는 도커 허브에서 여러 태그가 버전 정보처럼 제공된다. 태그를 넣지 않으면 latest로 지정된다. 파이썬 이미지를 사용하는 경우 Debian Buster 키워드가 있는게 유리하다.
  • 예시) FROM ubuntu:20.04

MAINTAINER

  • 일반적으로 이미지를 빌드한 작성자 이름과 이메일을 작성한다.
  • 예시) MAINTAINER sungjun.hwang <someone@gmail.com>

LABEL

  • 이미지 작성 목록으로 버전, 타이틀, 설명, 라이센스 정보 등을 작성한다. 1개 이상 작성이 가능하다.
  • 예시) LABEL purpose = 'Nginx for webserver' 여러개의 LABEL 따로 지정이 가능. 여러개를 쓰는 경우 아래처럼 권장된다.
권장사항
LABEL purpose = 'Nginx for webserver' \
	  version = '1.0' \

RUN

  • 설정된 기본 이미지에 패키지 업데이트와 각종 패키지 설치, 명령 실행 등을 작성한다. 1개 이상 작성이 가능하다.
  • RUN apt update
  • 권장사항: 다단계 빌드 사용 권장, 각 이미지별로 개별 Dockerfile로 빌드. 여러 설치 명령을 연결하면 이미지의 레이어 수 감소. autoremove, autoclen, rm -rf /var/lib/apt/lists/* 을 사용하면 저장되어 있는 apt 캐시가 삭제되므로 이미지 크기가 감소
  • 예시) Shell 방식(RUN apt update && apt install -y nginx)과 Exec 방식(RUN ["/bin/bash", "-c", "apt update])이 있음

CMD

  • 생성된 이미지를 컨테이너로 실행할 때 실행되는 명령로 ENTRYPOINT 명령문으로 지정된 커맨드에 디폴트로 넘길 파라미터를 지정할 때 사용한다. 여러 개의 CMD를 작성해도 마지막 하나만 처리된다. 일반적으로 이미지의 컨테이너 실행 시 애플리케이션 데몬이 실행되도록 하는 경우에 유용하다.
  • 예시) Shell 방식(CMD apachectl -D FOREGROUND)과 Exec 방식(CMD ["/usr/sbin/apachectl", "-D", "FOREGROUND"])

ENTRYPOINT

  • CMD와 마찬가지로 생성된 이미지가 컨테이너로 실행될 때 사용되지만, 컨테이너가 실행될 때 명령어 및 인자 값을 전달하여 실행한다는 점이 다르다. 여러 개의 CMD를 사용하는 경우 ENTRYPOINT 명령문과 함께 사용한다. ENTRYPOINT는 커맨드를 지정하고, CMD는 기본 명령을 지정하면 탄력적으로 이미지를 실행할 수 있다.
# 예시
ENTRYPOINT ["python"]
CMD ["runapp.py"]
  • ENTRYPOINT는 도커 컨테이너 실행 시 항상 수행해야 하는 명령어를 지정.
  • CMD는 도커 컨테이너 실행 시 다양한 명령어를 지정하는 경우 유용.

COPY

  • 호스트 환경의 파일, 폴더를 이미지 안에 복사하는 경우 작성한다.
  • 단순한 복사 작업만 지원한다. 빌드 작업 폴더의 외부의 파일은 COPY할 수 없다.
  • 예시) COPY <호스트OS 파일 경로> <Docker 컨테이너 안에서의 경로>

ADD

  • 호스트 환경의 파일, 폴더를 이미지 안에 복사하는 경우뿐만 아니라 URL 주소에서 직접 다운로드하여 이미지에 넣을 수 있고, 압축 파일인 경우에는 지정한 경로에 압축을 풀어서 추가한다.
  • 빌드 작업 폴더의 외부 파일은 ADD할 수 없고 폴더 추가 시에는 /로 끝나야 한다.
  • 예시) ADD <호스트OS 파일 경로> <Docker 컨테이너 안에서의 경로>

ENV

  • 이미지 안에 각종 환경 변수를 지정하는 경우 작성한다. 애플리케이션 사용을 쉽게 하려면 사전에 구성되어야 하는 환경 변수들이 있다.
  • 예시) ENV JAVA_HOME /usr/lib/jvm/java-8-oracle

EXPOSE

  • 컨테이너가 호스트 네트워크를 통해 들어오는 트래픽을 듣는 포트와 프로토콜을 지정하기 위해 작성한다.
  • 예시) EXPOSE 80 or EXPOSE 80/tcp

VOLUME

  • 볼륨을 이미지 빌드에 미리 설정하는 경우 작성한다.
  • VOLUME으로 지정된 컨테이너의 경로는 볼륨의 기본 경로 /var/lib/docker와 자동으로 연결된다
  • 예시) VOLUME /var/log or VOLUME ["/project"]

USER

  • 컨테이너의 기본 사용자는 root다.
  • 애플리케이션이 권한 없이 서비스를 실행할 수 있다면 USER를 통해 다른 사용자로 변경하여 사용한다.
  • 예시) USER sunhwang

WORKDIR

  • 컨테이너상에서 작업할 경로를 전환하기 위해 작성한다.
  • WORKDIR을 설정하면 RUN, CMD, ENTRYPOINT, COPY, ADD 명령문은 해당 폴더를 기준으로 실행한다.
  • 지정한 경로가 없으면 자동 생성되고 컨테이너 실행 이후 접속하면 지정한 경로로 연결된다.
  • 예시) WORKDIR /workspace

ARG

  • docker build 시점에서 변수값을 전달하기 위해 --build-arg=인자를 정의하여 사용한다.
  • 비밀 키, 계정 비밀번호 같은 민감한 정보 사용 시 이미지에 그대로 존재하여 노출될 위험이 있으므로 주의해야 한다.
  • 예시) ARG db_name(Dockerfile에 작성)
  • docker build --build_arg db_name=jpub_db .로 넘겨줄 수 있다.
  • CMD db_start.sh -h 127.0.0.1 -d ${db_name}으로 사용 가능.

ONBUILD

  • 처음 이미지 빌드에 포함하지만 실행되지 않고, 해당 이미지가 다른 이미지의 기본 이미지로 사용되는 경우 실행될 명령을 지정할 때 작성한다.
  • ONEBUILD 명령은 부모 Dockerfile이 자식 Dockerfile에 전달하는 방식이다.
  • 예시) ONEBUILD ADD websource.tar.gz /urs/share/nginx/html/

STOPSIGNAL

  • docker stop 명령은 컨테이너에 SIGTERM을 보내 정지한다. 다른 시그널을 넣고자 할 때 작성한다.
  • 예시) STOPSIGNAL SIGKILL # 시그널 번호나 이름을 넣으면 된다.

HEALTHCHECK

  • 컨테이너의 프로세스 상태를 체크하고자 하는 경우에 작성한다.
  • HEALTHCHECK는 하나의 명령만이 유효하고, 마지막에 선언된 것만 적용된다.
  • 예시) HEALTHCHECK --interval=1m --timeout=3s --retries=5 CMD curl -f http://localhost || exit 1

SHELL

  • Dockerfile 내부에서 사용할 기본 셀을 지정하는 경우 작성한다. 기본값으로 "/bin/sh"가 지정된다.
  • 예시) SHELL ["/bin/bash", "-c"]

책을 다 읽고나서 든 생각#

초반에는 도커에 대한 개념과 설명이 좋아서 공부가 많이 되었다. 후반부에는 실습 위주로 설명이 있었지만 도커 스웜 전에 가장 마지막 실습은 AWS 버전 차이로 뭔가 잘 안됐다. 중간중간 안되는 건 고치면서 했지만 마지막 클러스터 배포에서 어떤 이슈가 있어서 해결하지 못했다.

다 읽고나서도 아직까지 도커가 어려운 이유는 그래서 도커를 어떤 상황에 어떻게 쓰지가 계속 의문이다. 아무것도 없는 쌩 Dockerfile이 주어지고 내가 뭘 해야한다고 했을 때 무리없이 잘 할 수 있을까? 도커를 잘 쓰기 위해선 이 기술로 내가 이루고 싶은게 무엇인지 명확하게 정의해야 할 것 같다. 나도 내가 도커로 뭘 할 수 있을지도 모르고 뭘 해야 하는지도 불분명한 상황에서 좋은 기술을 배워봤자 잘 못 쓸 것 같다. 이런 인프라쪽 경험이 부족해서 마음껏 활용하지 못하는 게 답답하긴 하다.

중간에 읽다가 42서울 창업 부트캠프를 참여하는 8월달에는 이때를 만드느라 다른 것에 신경쓸 수 없었다.
그래도 9월 초에 끝나고 다시 책을 읽었는데 그 전까지 봤던 내용들이 전혀 생각나지 않아서 조금 이해하기 어려웠던 것도 있다.
그래도 이 책을 읽기보단 다른 책이나 영상, 공식 문서로 학습하는 것이 더 나은 방법일 것 같다.