[5/29] TIL - Docker 명령어, Docker Volume, Docker 환경 클린업, docker-compose[1]

Sangwon Jwa·2024년 5월 29일

데브코스 TIL

목록 보기
39/54
post-thumbnail

📖 학습 주제


  1. Docker 명령어 정리
  2. Docker Volume
  3. Docker 환경 클린업
  4. docker-compose
  5. 실습 - 멀티 컨테이너 소프트웨어

✏️ 주요 메모 사항 소개


Docker 명령어 정리

Image 관련

  • docker build --platform=linux/amd64 -t hjjwa1234/hangman : 이미지 생성
  • docker images, docker image ls : 이미지 리스트 출력
  • docker rmi ,docker image rm : 이미지 삭제

Docker Hub 관련

  • docker login -u 사용자ID -p 사용자PW : docker hub 사용자 정보를 로컬에 저장
  • docker pull hjjwa1234/sangwon : docker hub에서 이미지를 로컬로 다운로드
  • docker push hjjwa1234/hangman : 만든 이미지를 docker hub에 업로드

Container 관련

  • docker create : 컨테이너를 생성하지만 시작하지는 않음
  • docker run --name -p -v 이미지이름
    • --name : 컨테이너 이름 설정
    • -p : 호스트와 컨테이너 간의 포트 매핑
    • -v : 호스트와 컨테이너 간의 볼륨 매핑 (디렉토리 공유)
  • docker ps : 실행 중인 컨테이너 목록 확인
  • docker ps -a : 모든 컨테이너(실행 중이거나 중지된 것 모두) 목록 확인
  • docker ps -q : 실행 중인 컨테이너의 ID만 확인
  • docker stop 컨테이너이름(혹은 컨테이너ID) : 실행 중인 컨테이너 중지
  • docker start 컨테이너이름(혹은 컨테이너 ID) : 중지된 컨테이너 시작
  • docker restart 컨테이너이름(혹은 컨테이너 ID) : 컨테이너 재시작
  • docker kill 컨테이너이름(혹은 컨테이너 ID) : 컨테이너 강제 정지
  • docker pause 컨테이너이름(혹은 컨테이너 ID) : 컨테이너 일시 정지
  • docker unpuase 컨테이너이름(혹은 컨테이너 ID) : 일시 정지된 컨테이너 다시 시작
  • docker rm 컨테이너이름(혹은 컨테이너 ID) : 중지된 컨테이너 삭제

Container logs

  • docker logs -f 컨테이너이름 (혹은 컨테이너ID) : 실시간으로 컨테이너 로그 출력 (로그를 계속 따라감)
  • docker logs --tail 100 컨테이너이름 (혹은 컨테이너ID) : 컨테이너의 최근 100줄 로그 출력

exec

  • docker run --name=hangman hjjwa1234/hangman : hjjwa1234/hangman 이미지를 기반으로 hangman이라는 이름의 컨테이너를 생성하고 실행
  • docker exec hangman cat /etc/hosts : 컨테이너 내에서 /etc/hosts 파일의 내용을 출력 (exec은 실행중인 컨테이너와 상호작용 하는 명령어)

detach & attach

  • docker run -d hjjwa1234/hangman : hjjwa1234/hangman 이미지를 기반으로 컨테이너를 백그라운드(detached)에서 실행
  • docker attach 컨테이너ID : 실행 중인 컨테이너에 연결하여 실시간 출력 및 입력에 접근

Volume

  • docker volume ls : 모든 Docker 볼륨 목록을 나열
  • docker volume rm : 특정 Docker 볼륨 삭제
  • docker volume prune : 사용하지 않는 모든 Docker 볼륨 삭제
  • docker volume inspect : 특정 Docker 볼륨의 세부 정보 조회

Docker Container의 일생


Docker Volume

Docker Container가 무슨 이유든 중단되고 재실행된다면, 그 전의 데이터는 어떻게 되는 걸까?

특정 소프트웨어가 Docker Container를 통해 일회성으로 동작하는 것이 아니라 계속해서 동작해야 한다면 데이터가 영구적으로 보관되어야 한다. 예를 들어 데이터베이스가 Docker Container안에서 동작하는 경우가 있다.

이를 보장하는 기능이 Docker Volume이다.(Data Persistence) Docker Volume은 Docker Container내의 가상 파일 시스템과 호스트 시스템의 파일 시스템을 맵팽하여 처리한다.

  • 예) 호스트 파일 시스템의 /home/hjjwa1234/logs를 Docker Container의 /var/lib/airflow/logs로 맵핑
  • Container와 Host 시스템이 특정 폴더를 공유한다고 생각하면 된다.
  • 이 경우 Docker Container가 중단되더라도 모든 Airflow logs는 기록이 남게 됨

Docker Volume 타입

  1. Host Volumes : docker run -v를 실행할 때 페어로 지정
    • docker run -v /home/hjjwa1234/logs:/var/lib/airflow/logs
    • :앞에 호스트 파일 시스템 path이고 뒤가 컨테이너 파일 시스탬 path

 

  1. Anonymous Volumes : docker run -v를 실행할 때 컨테이너 패스만 지정
    • docker run -v /var/lib/mysql/data
    • 이 방식이 Dockerfile에서 사용되는 방식으로 호스트쪽에 액세스되지는 않지만 재시작해도 유지됨

 

  1. Named Volumes : docker run -v를 실행할 때 이름과 컨테이너 패스를 지정
    • docker run -v name:/var/lib/mysql/data
    • 가장 선호되는 방식으로, 하나의 Volume을 다수의 컨테이너에서 공유하는 것도 가능하다
    • 이 포맷으로 뒤에서 살펴볼 docker-compose에서도 사용된다
  • Volume을 Readonly로 지정하고 싶다면
    • name:/var/lib/mysql/data:ro

사용법

이미지 생성 시 Docker Volume을 사용하는 방법은 두 가지가 있다.

  1. Dockerfile
    • VOLUME 명령을 통해 anonymous volume만 지정이 가능
  2. docker-compose
    • Host Volume이나 Named Volume을 사용하는 것이 일반적

 

Docker Volume을 docker-compose.yml에서 사용하는 예를 한번 살펴보자.

  • Airflow 예)
volumes:
  - ${AIRFLOW_PROJ_DIR:-.}/dags:/opt/airflow/dags
  - ${AIRFLOW_PROJ_DIR:-.}/logs:/opt/airflow/logs
  - ${AIRFLOW_PROJ_DIR:-.}/plugins:/opt/airflow/plugins

이렇게 작성한다면 호스트 파일시스템(airflow-setup/dags)의 내용과 Docker Container 파일시스템(/opt/airflow/dags)의 내용이 같아야 한다.

 


실습

실제로 사용해보는 연습을 하기 위해 nginx를 실행해보자. nginx는 경량화된 웹서버로, 많은 경우 Load Balancer로 사용되기도 한다. 실행 과정은 다음과 같다.

  • docker run -d --name=nginx -p 8081:80 nginx
  • 브라우저 방문 : http://localhost:8081/
  • docker exec --user=root -it nginx sh
    • apt update
    • apt install nano
    • nano /usr/share/nginx/html/index.html (내용 : Welcome to Docker Volume)
    • exit
  • docker restart nginx
    • 위 과정을 반복해 /usr/share/nginx/html/index.html 내용 확인 시 원상복구된 것을 볼 수 있음

 

다음으로 -v 옵션과 함께 nginx를 실행하는 작업도 진행해보자. (파일 경로는 자신의 환경에 맞게 수정)

  • ls -tl /Users/jobox/Downloads/grepp/kdt/nginx/html
    • index.html
    • test.html
  • docker run -p 8081:80 -d --name nginx_demo -v /Users/jobox/Downloads/grepp/kdt/nginx/html:/usr/share/nginx/html nginx
  • http://localhost:8081
  • index.html 내용을 수정하고 브라우저에서 재방문
  • nginx를 재시작하고 내용이 유지되는지 확인

이번엔 nginx 디렉토리와 우리가 만든 html파일이 들어있는 디렉토리를 맵핑해서 출력값이 달리진 것을 확인할 수 있다.

다시 nginx 컨테이너를 stop하고 rm한다음 실행하면 내용이 계속해서 반영이 되어있다.

실행 중에 index.html을 변경하면 곧바로 웹 브라우저에서도 변경이 이뤄지는 것을 확인할 수 있다.


Docker 환경 클린업

Docker 컨테이너를 여러개 올리고 실행하다 보니 환경이 꼬이고 복잡해지는 상황이 있을 수 있다. 그럴때는 환경을 정리하는 프로세스가 필요할 수 있다.

커맨드라인

Docker Desktop에서 삭제하는 것이 가장 직관적이긴 하지만 커맨드로 진행할 수도 있다. Image를 삭제하려면 먼저 실행 중인 Container가 없어야 하기 때문에 먼저 Container를 중단하고, 다음으로 Image를 삭제하면 된다

  • 컨테이너 삭제

    • 원래는 docker container ls를 하고 Container Id를 개별적으로 docker container rm 뒤에 추가해야함
    • 한번에 여러개를 실행하려면 다음과 같이 커맨드를 실행
    • docker container rm -f $(docker container ls -aq)
  • 이미지 삭제

    • 원래는 docker image ls를 하고 Image Id를 개별적으로 docker image rm뒤에 추가해야함
    • 한번에 여러개를 실행하려면 다음과 같이 커맨드를 실행
    • docker image rm $(docker image ls -q)
  • 확인 작업

    • docker ps
    • docker images

Docker Desktop

Docker Desktop을 이용한다면 Troubleshoot 메뉴에서 Clean / Purge data를 이용해서 삭제할 수 있다.


docker-compose

Docker Compose는 다중 컨테이너 Docker 애플리케이션을 정의하고 실행하기 위한 도구이다. YAML 파일을 사용해 애플리케이션의 서비스, 네트워크, 볼륨 설정을 선언적으로 구성할 수 있다. 이를 통해 단일 명령으로 복잡한 애플리케이션 스택을 손쉽게 관리하고 배포할 수 있다.

예를들어 우리가 사용했던 Airflow의 docker-compose.yml 파일을 보면 다음과 같이 여러개의 컨테이너들이 하나의 파일로 정의되어 있는 것을 볼 수 있다.


실습 - 멀티 컨테이너 소프트웨어

프로그램 개요

저번 시간에 만든 Hangman 프로그램은 하나의 Container로 구성되어 있었는데 만일 다수의 Container로 구성된 프로그램이라면 어떻게 이미지를 빌드해야할까?

우리가 다운로드 받아서 실행해볼 프로그램은 Voting application이라는 이름으로, 고양이나 개를 투표하는 간단한 투표 프로그램이다. (Github repo : https://github.com/dockersamples/example-voting-app)

이 프로그램은 다음과 같은 총 5개의 컨테이너로 구성된다.

이번 실습에서는 5가지의 컨테이너를 매뉴얼하게 실행하는 실습을 진행할 예정이다. docker-compose를 이용한 실행은 다음 포스트에서 다룰 예정


이미지 만들기(build)

일단 이 프로그램을 git clone 명령어를 사용해서 local 환경에 복사하자.

이제 이미지를 만들어야 하는데(build) PostgreSQL과 redis는 Docker Hub의 Official Image를 사용하면 되기 때문에 나머지 voting-app, result-app, Worker만 이미지를 만들면 된다.

Postgres와 redis 는 docker run 명령어를 사용해서 바로 official image를 다운받고 실행해보자.

이미지 리스트를 출력해보면 다섯개의 이미지가 잘 생성이 된 것을 볼 수 있다.


네트워크 설정(docker network)

이제 이 컨테이너를 일일히 수동으로 docker run을 해서 실행하면 원하는 대로 동작하지 않을 것이다. 왜냐하면 각각의 컨테이너가 별개의 공간에서 실행이 되고 있어서 다른 컨테이너의 정보를 모르기 때문에 각 컴포넌트들 간의 네트워크 연결이 안되고 있기 때문이다. 따라서 네트워크와 관계된 Docker 기능을 사용해야 한다.

네트워크 관련 이슈를 자세히 살펴보기 위해서 각 컴포넌트의 코드를 살펴보자.

결국에 코드에 인자로 들어가는 "redis", "db" 이런 것들을 코드에서 알 수가 없기 때문에 동작하지 않는 현상이 일어나는 것이다. 이를 해결하기 위해서 docker의 network 기능을 사용해보자. (전에는 docker runlink 옵션을 사용)

  • network를 하나 만들고 모든 컨테이너들을 이 네트워크 안으로 지정
    • 연결 상황에 따라 별개의 네트워크를 만들고 사용도 가능
      • back-tier
      • front-tier
    • 매뉴얼 예제에서는 mynetwork를 하나 만들고 진행할 예정

docker의 network 기능을 이용하여 각 컨테이너를 연결하는 과정을 차례대로 설명하자면 다음과 같다

  1. 모든 Docker 컨테이너를 삭제
    • docker container rm -f $(docker container ls -aq)
  2. mynetwork라는 이름의 새로운 Docker 네트워크를 생성
    • docker network create mynetwork
  3. redis라는 이름의 컨테이너를 생성하고, 이를 mynetwork 네트워크에 연결하여 백그라운드에서 실행
    • docker run -d --name=redis --network mynetwork redis
  4. db라는 이름의 컨테이너를 생성하고, PostgreSQL 데이터베이스 비밀번호를 설정한 후 mynetwork 네트워크에 연결하여 백그라운드에서 실행
    • docker run -d --name=db -e POSTGRES_PASSWORD=password --network mynetwork postgres
  5. vote라는 이름의 컨테이너를 생성하고, 호스트의 포트 5001을 컨테이너의 포트 80에 매핑한 후 mynetwork 네트워크에 연결하여 백그라운드에서 실행
    • docker run -d --name=vote -p 5001:80 --network mynetwork vote
  6. result라는 이름의 컨테이너를 생성하고, 호스트의 포트 5002를 컨테이너의 포트 80에 매핑한 후 mynetwork 네트워크에 연결하여 백그라운드에서 실행
    • docker run -d --name=result -p 5002:80 --network mynetwork result
  7. worker라는 이름의 컨테이너를 생성하고, 이를 mynetwork 네트워크에 연결하여 백그라운드에서 실행
    • docker run -d --name=worker --network mynetwork worker

docker ps 명령어를 이용해서 현재 실행중인 컨테이너를 확인하면 5개 모두 잘 돌아가고 있는 걸 확인할 수 있다.


결과 확인

이제 브라우저에 가서 투표 기능이 잘 작동되고, 오류는 없는지 확인해보자.

5개의 컨테이너를 따로 올렸을 때는 메인 페이지에서 CATS 나 DOGS를 선택하면 오류 페이지가 나왔는데 이제 잘 선택이 되는 것을 볼 수 있다.

제대로 연결되었는지 확인하기 위해서 ping 기능을 이용해서 vote 컨테이너에서 redis와 연결이 되는지 확인해보자. vote 컨테이너 안에는 ping이 설치되어 있지 않기 때문에 exec 명령어를 사용해서 vote 컨테이너 안에 ping을 설치해주자.

  • docker exec -it -user root vote sh
  • apt update
  • apt install iputils-ping
  • ping redis

ping 결과를 보면 redis.mynetwork 와 연결이 잘 되고 있는 것을 확인할 수 있다.

0개의 댓글