
- Docker 명령어 정리
- Docker Volume
- Docker 환경 클린업
- docker-compose
- 실습 - 멀티 컨테이너 소프트웨어
docker build --platform=linux/amd64 -t hjjwa1234/hangman : 이미지 생성docker images, docker image ls : 이미지 리스트 출력docker rmi ,docker image rm : 이미지 삭제docker login -u 사용자ID -p 사용자PW : docker hub 사용자 정보를 로컬에 저장docker pull hjjwa1234/sangwon : docker hub에서 이미지를 로컬로 다운로드docker push hjjwa1234/hangman : 만든 이미지를 docker hub에 업로드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) : 중지된 컨테이너 삭제docker logs -f 컨테이너이름 (혹은 컨테이너ID) : 실시간으로 컨테이너 로그 출력 (로그를 계속 따라감)docker logs --tail 100 컨테이너이름 (혹은 컨테이너ID) : 컨테이너의 최근 100줄 로그 출력docker run --name=hangman hjjwa1234/hangman : hjjwa1234/hangman 이미지를 기반으로 hangman이라는 이름의 컨테이너를 생성하고 실행docker exec hangman cat /etc/hosts : 컨테이너 내에서 /etc/hosts 파일의 내용을 출력 (exec은 실행중인 컨테이너와 상호작용 하는 명령어)docker run -d hjjwa1234/hangman : hjjwa1234/hangman 이미지를 기반으로 컨테이너를 백그라운드(detached)에서 실행docker attach 컨테이너ID : 실행 중인 컨테이너에 연결하여 실시간 출력 및 입력에 접근docker volume ls : 모든 Docker 볼륨 목록을 나열docker volume rm : 특정 Docker 볼륨 삭제docker volume prune : 사용하지 않는 모든 Docker 볼륨 삭제docker volume inspect : 특정 Docker 볼륨의 세부 정보 조회
Docker Container가 무슨 이유든 중단되고 재실행된다면, 그 전의 데이터는 어떻게 되는 걸까?

특정 소프트웨어가 Docker Container를 통해 일회성으로 동작하는 것이 아니라 계속해서 동작해야 한다면 데이터가 영구적으로 보관되어야 한다. 예를 들어 데이터베이스가 Docker Container안에서 동작하는 경우가 있다.
이를 보장하는 기능이 Docker Volume이다.(Data Persistence) Docker Volume은 Docker Container내의 가상 파일 시스템과 호스트 시스템의 파일 시스템을 맵팽하여 처리한다.
docker run -v를 실행할 때 페어로 지정docker run -v /home/hjjwa1234/logs:/var/lib/airflow/logs
docker run -v를 실행할 때 컨테이너 패스만 지정docker run -v /var/lib/mysql/data
docker run -v를 실행할 때 이름과 컨테이너 패스를 지정docker run -v name:/var/lib/mysql/dataname:/var/lib/mysql/data:ro이미지 생성 시 Docker Volume을 사용하는 방법은 두 가지가 있다.
Docker Volume을 docker-compose.yml에서 사용하는 예를 한번 살펴보자.
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 nginxdocker exec --user=root -it nginx shdocker restart nginx




다음으로 -v 옵션과 함께 nginx를 실행하는 작업도 진행해보자. (파일 경로는 자신의 환경에 맞게 수정)
ls -tl /Users/jobox/Downloads/grepp/kdt/nginx/htmldocker run -p 8081:80 -d --name nginx_demo -v /Users/jobox/Downloads/grepp/kdt/nginx/html:/usr/share/nginx/html nginx
이번엔 nginx 디렉토리와 우리가 만든 html파일이 들어있는 디렉토리를 맵핑해서 출력값이 달리진 것을 확인할 수 있다.


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

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


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 psdocker imagesDocker Desktop을 이용한다면 Troubleshoot 메뉴에서 Clean / Purge data를 이용해서 삭제할 수 있다.


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를 이용한 실행은 다음 포스트에서 다룰 예정
일단 이 프로그램을 git clone 명령어를 사용해서 local 환경에 복사하자.

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

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


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

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

결국에 코드에 인자로 들어가는 "redis", "db" 이런 것들을 코드에서 알 수가 없기 때문에 동작하지 않는 현상이 일어나는 것이다. 이를 해결하기 위해서 docker의 network 기능을 사용해보자. (전에는 docker run의 link 옵션을 사용)
network를 하나 만들고 모든 컨테이너들을 이 네트워크 안으로 지정docker container rm -f $(docker container ls -aq)docker network create mynetworkdocker run -d --name=redis --network mynetwork redisdocker run -d --name=db -e POSTGRES_PASSWORD=password --network mynetwork postgresdocker run -d --name=vote -p 5001:80 --network mynetwork votedocker run -d --name=result -p 5002:80 --network mynetwork resultdocker 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 shapt updateapt install iputils-pingping redisping 결과를 보면 redis.mynetwork 와 연결이 잘 되고 있는 것을 확인할 수 있다.
