[DEV] 11주차. Docker & K8s (3)
1. Docker Volume
필요성
- Docker Container가 실행되었다면 중단되면 데이터들은 어떻게 될까?
- 특정 소프트웨어가 컨테이너를 통해 일회성으로 동작하는 것이 아니라 계속해서 동작해야 한다면 데이터가 영구적으로 보관되어야 함
- ex) 데이터베이스가 컨테이너 안에서 동작한다면?
- 이를 보장하는 기능이 Docker Volumes => Docker Persistence
- Docker Container 내의 가상 파일 시스템과 호스트 시스템의 파일 시스템을 맵핑
- ex) 호스트 파일 시스템의 /home/bokyung/logs를 Docker Contiainer의 /var/lib/airflow/logs로 맵핑
- 이 경우 Docker Container가 중단되더라도 모든 Airflow log는 기록이 남게 됨
- Docker Container로 MySQL을 실행하는 경우 데이터가 저장되는 공간을 Docker Volume으로 설정
Docker Volume
- 호스트 파일 시스템 폴더를 Docker Container 파일 시스템의 폴더로 마운트하는 것
- 호스트쪽에서 내용을 바꾸면 바로 Docker Container쪽에도 반영됨
- 이를 통해 Docker Container의 상태와 상관없이 데이터를 영구적으로 보관
- 파일 시스템의 마운트
- 원래 마운트란 디스크와 같은 물리적인 장치를 파일 시스템의 특정 위치(폴더)에 연결해주는 것을 말함
Docker Volume 타입
- Host Volumes :
docker run -v
를 실행할 때 페어로 지정docker run -v [host folder]:[container folder]
- 호스트 파일 시스템 path : 컨테이너 파일 시스템 path
- Anonymous Volumes :
docker run -v
를 실행할 때 컨테이너 경로만 지정docker run -v [container folder]
- 데이터는 영구적으로 저장하고 싶지만, 호스트 파일 시스템에서 그 내용을 볼 일은 없는 경우
- Dockerfile에서 사용되는 방식
- 호스트쪽에 액세스되지는 않지만 재시작해도 유지됨
- Named Volumes :
docker run -v
를 실행할 때 이름과 컨테이너 경로만 지정docker run -v name:[container folder]
- 가장 선호되는 방식!
- 이 방식이 하나의 Volume을 다수의 컨테이너에서 공유하는 것도 가능하게 해줌
- 이 포맷으로 뒤에서 살펴볼 docker-compose에서도 사용됨
- Volume을 Readonly로 지정하고 싶다면
- path에
:ro
옵션 추가 name:/var/lib/mysql/date:ro
- path에
이미지 생성시 Docker Volume 사용법
- Dockerfile
VOLUME
명령으로 Anonymous Volume만 사용 가능
- docker-compose
- Host Volume이나 Named Volume을 사용하는 것이 일반적
Docker Volume 사용 예 1) nginx 실행
- nginx
- 경량화된 웹서버
- 많은 경우 로드밸런서로 사용됨
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
내용 편집exit
docker restart nginx
- 위 과정을 반복해 /usr/share/nginx/html/index.html 내용 확인시 원상복구된 것을 볼 수 있음
Docker Volume 사용 예 2) -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를 재시작하고 내용이 유지되는지 확인
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
- MySQL_to_Redshift_v2.py
- UpdateSymbol_v3.py
- UpdateSymbol.py
- Docker Container 파일 시스템: /opt/airflow/dags
docker exec [container id] ls -tl /opt/airflow/dags
- MySQL_to_Redshift_v2.py
- UpdateSymbol_v3.py
- UpdateSymbol.py
- 위 둘의 내용이 동일해야 함!
2. Docker 환경 클린업
커맨드라인
- Docker Desktop에서 모두 삭제하는 것이 가장 직관적이긴 함
- 이미지를 삭제하려면 먼저 실행 중인 컨테이너가 없어야 함
- 먼저 컨테이너를 중단하고 다음으로 이미지 삭제
- 컨테이너 삭제
- 원래)
docker container ls
->docker container rm [container id]
- 동시에 삭제도 가능
- but 여러 개를 삭제할 때 모두 copy하는 것이 번거로움
- 한번에)
docker container rm -f ${docker container ls -aq}
-q
옵션: ID만 반환
- 원래)
- 이미지 삭제
- 원래)
docker image ls
->docker image rm [image id]
- 한번에)
docker image rm -f ${docker image ls -q}
- 원래)
- 다 삭제되었는지 확인
docker ps
docker images
전부 삭제됨!
zsh: bad substitution
오류
- MAC 터미널에서
${}
사용 시 해당 오류 발생 $()
으로 사용해야 함!
Desktop
- 가장 직관적
- [Troubleshoot 메뉴] - [Clean/Purge data] 선택
3. 다수의 Container로 구성된 소프트웨어 실행 (voting application)
Voting application
https://github.com/dockersamples/example-voting-app
- Docker에서 제공해주는 예제 프로그램
build
git clone https://github.com/dockersamples/example-voting-app
cd example-voting-app
docker build -t vote ./vote
docker build -t result ./result
docker build -t worker ./worker
docker images
네트워크 관련 이슈
- vote/app.py
def get_redis():
if not hasattr(g, 'redis'):
g.redis = Redis(host="redis", db=0, socket_timeout=5)
return g.redis
- vote에 로그인해서 iputils-ping 설치 후
ping
명령으로 redis 호스트 이름이 연결되는지 확인
ping redis
- result/server.js
var pool = new pg.Pool({
connectionString:
'postgres://postgres:postgres@db/postgres'
})
- Postgres 연결 시
postgres:postgres
를 사용하고 있음을 주의깊게 볼 것!
- worker/Program.cs
var pgsql = OpenDbConnection("Server=db;Username=postgres;Password=postgres;");
var redisConn = OpenRedisConnection("redis");
network 이슈 해결
- docker의 네트워크 기능 사용
- 이전에는 docker run의 link 옵션 사용
- network를 하나 만들고 모든 컨테이너들을 이 네트워크 안으로 지정
- 연결 상황에 따라 별개의 네트워크를 만들어 사용도 가능함
- back-tier
- front-tier
- 매뉴얼 예제에서는 mynetwork을 하나 만들고 진행 예정
- 연결 상황에 따라 별개의 네트워크를 만들어 사용도 가능함
run
- 일일히 하나씩 실행하면 각 컴포넌트들 간의 네트워크 연결이 되지 않음!
docker network create mynetwork
docker run -d --name=redis --network mynetwork redis
docker run -d --name=db -e POSTGRES_PASSWORD=pwd --network mynetwork postgres
docker run -d --name=vote -p 5001:80 --network mynetwork vote
docker run -d --name=result -p 5002:80 --network mynetwork result
docker run -d --name=worker --network mynetwork worker
# 외부에서 access할 필요가 없는 모듈 -> 포트 맵핑 X
docker container ls