# Docker 개요
개발 환경 구성에 대한 문서를 계속 업데이트한다면 이런 문제가 최소화되겠지만, 상상하는 것만으로도 진이 빠지는 일인 건 분명
# Docker 적용하기
1. local에서 프로젝트 폴더를 생성하고자 하는 경로에서, git clone해오거나, usb에서 프로젝트 폴더를 복사
2. 프로젝트 루트 디렉토리에서 도커 이미지 빌드 및 생성
[cmd] cd 프로젝트폴더경로
[cmd] docker build -t (도커이미지이름)
(ex) docker build -t sdweb-docker-img
// sdweb-docker-img라는 도커 이미지가 생성됨
// 아래의 명령어로 생성된 docker 조회 가능
[cmd] docker image ls | grep (검색어)
(ex) docker image ls | grep sdweb-docker-img
3. 프로젝트 앱 컨테이너 실행 (2번의 이미지를 컨테이너로 실행)
[cmd] docker run -it --rm -p 8000:8000 sdweb-docker-img ./실행파일..?
// 데이터 베이스가 연결되어 있지 않기 때문에 에러남
4. 데이터베이스 컨테이너 실행
[cmd] docker run -it --rm (db도커이미지명)
(ex) docker run -it --rm protgres
// 기본적으로 도커 컨테이너들은 각각 격리된 환경에서 실행
// 다시 말해, 별도의 옵션을 지정하지 않으면 다른 컨테이너의 존재를 알 수 없음. 각각 실행만 시키면 무의미
5. 데이터베이스 컨테이너 연결
- 데이터베이스 컨테이너를 실행하면서 컨테이너 이름을 붙이고(db라고 하죠),
- 앱 컨테이너를 실행할 때 db 컨테이너를 연결해 줍니다.
docker run --rm(-it 노테이션 삭제함으로써 데몬 형태로 컨테이너 실행)\
--name db(db 컨테이너 이름 붙임) \
-e POSTGRES_DB=djangosample(-e 노테이션으로 컨테이너 내 환경변수설정) \
-e POSTGRES_USER=sampleuser \
-e POSTGRES_PASSWORD=samplesecret \
postgres(db도커이미지명)
// 도커 허브의 공식 포스트그레SQL 저장소에 가보면 설정할 수 있는 환경 변수 종류가 존재
// 여기서 설정한 사용자 이름이나 비밀번호, 데이터베이스 이름 같은 환경변수들은
sdweb프로젝트폴더/settings.ts 파일 안에 설정해 둔 기본값들이다.(프로젝트가 알고 있는 값)
6. 앱 컨테이너 실행 및 데이터베이스 컨테이너 연결(link)
docker run -it --rm \
-p 8000:8000(앞의 8000은 도커를 설치한 호스트의 8000포트를, 컨테이너의 8000번 포트에 연결한다) \
--link db(db 컨테이너 이름 붙였던 것,--link: 참조할 다른 컨테이너를 지정) \
-e DJANGO_DB_HOST=db \
-e DJANGO_DEBUG=True \
sdweb-docker-img \
./manage.py runserver 0:8000(마지막 줄은 프로젝트 속성에 따라 실행 명령어 달라질 듯)
// 연동도 완료되지만, 소스코드를 변경해도, 결과가 반영이 안되는 문제가 존재
// 프로젝트 폴더에 생성된 Dockerfile을 분석해 보면 10행의 ADD ./sdweb /app/sdweb/ 이라는 명령어를 통해
// 컨테이너 밖의 소스를 컨테이너 안에 추가함으로써, 격리되어 더이상 소스코드 변경에 영향 받지 않음
// 수정할 소스 코드의 디렉터리를 앱 컨테이너 내부의 소스 코드와 연결하여,
// 코드를 바꿀 때마다 컨테이너 속 코드도 바뀌게 하는 작업이 필요
7. 코드 변경이 실시간으로 반영되게 하기
// 기존 앱컨테이너 종료(Ctrl + C)
docker run -it --rm \
-p 8000:8000 \
--link db \
-e DJANGO_DB_HOST=db \
-e DJANGO_DEBUG=True \
--volume=$(pwd):/app/(--volume: 이 옵션을 사용하여 로컬 디렉터리의 특정 경로를 컨테이너 내부로 마운트, ($(pwd)는 이 명령을 실행하는 현재 디렉터리의 절대 경로, app폴더는 로컬디렉토리에서 격리된 컨테이너로 마운트할 수 있게 된다.) \
sdweb-docker-img \
./manage.py runserver 0:8000
8. 컨테이너 종료하기
// 앱 컨테이너 종료(Ctrl + C)
// 데이터베이스 컨테이너 종료
[cmd] docker stop db(기존에 지정했던 이름)
9. 데이터베이스 데이터 보존
// 컨테이너 실행시 --rm 옵션을 지정할 경우, 데이터베이스 컨테이너가 종료와 함꼐 사라짐
// 그와 동시에 컨테이너 내부에 쌓였던 데이터베이스 데이터들도 모두 삭제(깔끔하지만, 개발용 데이터 매번 쌓기 귀찮)
// 데이터베이스가 데이터를 저장할 때 파일 시스템을 사용한다는 점을 생각해보면, 이를 해결할 때도 역시 --volume 옵션을 사용
$ mkdir -p ./docker/data //프로젝트 경로 내에서 'docker/data'라는 폴더 생성(이름 임의 지정 가능)
$ docker run -it --rm \
--name db \
-e POSTGRES_DB=djangosample \
-e POSTGRES_USER=sampleuser \
-e POSTGRES_PASSWORD=samplesecret \
--volume=$(pwd)/docker/data:/var/lib/postgresql/data \
// 가운데 ':' 기호를 유의
// 데이터베이스 컨테이너 내부의 디렉터리(/var/lib/postgresql/data)를
// 로컬 컴퓨터의 디렉터리($(pwd)/docker/data)로 연결
postgres:
// 이제 데이터베이스가 데이터를 저장할 파일 시스템으로 로컬 컴퓨터의 $(pwd)/docker/data 폴더를 사용
# 정리(순서 유의)
1. 데이터베이스 컨테이너 실행
docker run -it --rm \
--name db \
-e POSTGRES_DB=djangosample \
-e POSTGRES_USER=sampleuser \
-e POSTGRES_PASSWORD=samplesecret \
--volume=$(pwd)/docker/data:/var/lib/postgresql/data \
postgres
2. 새 터미널 창에서 앱 컨테이너 실행
docker run -it --rm \
-p 8000:8000 \
--link db \
-e DJANGO_DB_HOST=db \
-e DJANGO_DEBUG=True \
--volume=$(pwd):/app/ \
django-sample \
./manage.py runserver 0:8000
// 위의 두개 명령어만으로도, DB와 잘 연결되고, 소스코드 변경하면 개발서버가 알아서 재시작
// 컨테이너를 종료해도 DB가 로컬에 저장
# Docker-compose로 개발 환경 구성하기
컨테이너 실행에 필요한 옵션을 docker-compose.yml이라는 파일에 적어두고, 컨테이너 간 실행 순서와 의존성을 관리하자!
1. docker-compose.yml 파일 만들기
- 장황한 도커 실행 옵션을 미리 적어둔 문서
- 프로젝트 루트에 파일을 만든다.
version: '3' // 파일 규격(규격에 따라 지원하는 옵션 달라짐, 3으로 시작하는 최신버전 사용) services: // 해당 항목 밑에 실행하려는 컨테이너 정의(containers == services) db: // postgres docker이미지 서비스의 이름을 db로 지정하였음 image: postgres // 해당 서비스(db라는 컨테이너)가 사용할 도커이미지명
// postgres 명칭은 dockerhub의 공식 postgres 이미지
volumes: // 컨테이너 내부 폴더와 로컬 폴더 사이의 마운트 관계 지정(격리를 푸는 연결 통로) - ./docker/data:/var/lib/postgresql/data // './'은 로컬의 루트프로젝트 폴더경로
// 컨테이너 내 var/lib/portgresql/data를 로컬 내 projectRoot/docker/data로 마운트 environment: // 컨테이너 내부의 환경변수 지정(docker run 명령어의 -e 옵션과 대응) - POSTGRES_DB=sampledb - POSTGRES_USER=sampleuser - POSTGRES_PASSWORD=samplesecret - POSTGRES_INITDB_ARGS=--encoding=UTF-8 // 데이터베이스 서버의 인코딩 설정 sdweb: // 앱 서비스의 이름을 sdweb으로 지정 build: // db 컨테이너 서비스와 다르게 앱은 특정 이미지(redis, postgres...) 대신 build 옵션을 추가 context: . // docker build 명령을 실행할 디렉토리 경로 dockerfile: ./compose/django/Dockerfile-dev //<개발용> 도커이미지를 빌드하는데 사용할 Dockerfile 지정
//개발용 Dockerfile-dev에서는 소스코드를 앱 컨테이너에 넣지 않음(로컬 소스가 실시간 반영이 안되므로) environment: // 앱 서비스의 환경 변수로 지정(DB 접속정보는 db 서비스에 입력한 것과 동일해야함) - DJANGO_DEBUG=True // 각 값들을 프로젝트 소스 내의 설정관련된 부분에서 불러와 사용 - DJANGO_DB_HOST=db - DJANGO_DB_PORT=5432 - DJANGO_DB_NAME=sampledb - DJANGO_DB_USERNAME=sampleuser - DJANGO_DB_PASSWORD=samplesecret - DJANGO_SECRET_KEY=dev_secret_key ports: // docker run 명령어의 -p 옵션에 해당하는 부분(포트 지정) - "8000:8000" command: // 앱 컨테이너를 실행시 가장 마지막에 적었던 명령어 부분 - python manage.py runserver 0:8000 volumes: // docker run 명령어의 -volumes 옵션에 해당하는 부분(마운트 지정)
- ./:/app/ // 컨테이너 내 app 폴더를 로컬 내 루트 프로젝트 폴더로 마운트
# docker-compose 명령어 실행
[yml파일이 있는루트 프로젝트 폴더경로] docker-compose up -d
// http://127.0.0.1:8000에 접속해보면 개발 서버가 잘 작동함을 확인 가능
// up -d : yml 파일 내용에 따라 이미지를 BUILD하고, 서비스(컨테이너)를 실행합니다.
// -d: 서비스 실행 후 콘솔로 빠져나옵니다.
// --force-recreate: 컨테이너를 지우고 새로 만듭니다.
// --build: 서비스(컨테이너) 시작 전 이미지를 새로 만듭니다.
(dock run 명령어로 자동생성되는 운영환경설정기록인 Dockfile로 build하여 동일한 이미지를 만든다.)
(이미지를 통해 격리된 컨테이너를 생성한다.)
1. 서비스를 띄울 네트워크 설정
2. 필요한 볼륨 생성(혹은 이미 존재하는 볼륨과 연결)
3. 필요한 이미지 풀(pull)
4. 필요한 이미지 빌드(build)
5. 서비스 의존성에 따라 서비스 실행
[루트 프로젝트 폴더경로] docker-compose ps : 현재 환경에서 실행중인 각 서비스의 상태 조회
[루트 프로젝트 폴더경로] docker-compose stop : 현재 환경에서 실행중인 서비스를 멈춥니다.
[루트 프로젝트 폴더경로] docker-compose start : 현재 환경에서 실행중인 서비스를 시작합니다.
[루트 프로젝트 폴더경로] docker-compose down --volume: 현재 환경에서 컨테이너, 네트워크 삭제, 또는 볼륨까지도 삭제
[루트 프로젝트 폴더경로] docker-compose exec (명령어) : 실행 중인 컨테이너에서 명령어 실행
[루트 프로젝트 폴더경로] docker-compose logs (서비스,컨테이너명) : 서비스명 없으면 모든 서비스의 로그
-f: 지금까지 쌓인 로그를 다 보여준 후에도 셸로 빠져나오지 않고, 로그가 쌓일 때마다 계속해서 출력합니다.
# 단축명령어 적용하기(맥 또는 리눅스)
~/.bashrc나 ~/.zshrc 파일 상에 alias 적용
alias dco='docker-compose'
alias dcb='docker-compose build'
alias dce='docker-compose exec'
alias dcps='docker-compose ps'
alias dcr='docker-compose run'
alias dcup='docker-compose up'
alias dcdn='docker-compose down'
alias dcl='docker-compose logs'
alias dclf='docker-compose logs -f'
# docker-compose 버전 차이
- 2 : links 항목을 통해 연결할 컨테이너 지정해주어야 했음
- 3 : 동일 네트워크 안에 있는 서비스끼리 서로 통신 가능
# tip
1. docker-compose.yml 수정 후, 서비스들에 적용하길 원하는 경우
docker-compose.yml 파일을 수정하고 이를 서비스에 적용하려면 서비스를 멈추고(stop), 서비스를 지우고(rm), 서비스를 시작해야(up) 합니다.
하지만 up 명령만 실행해도, (현재 실행 중인 서비스 설정과 달라진 부분이 있다면) 알아서 컨테이너를 재생성하고 서비스를 재시작해줍니다.*
2. Dockerfile-dev 파일 수정 후, 서비스들에 적용하길 원하는 경우
up 명령에 다음과 같이 --build 옵션을 넣으면 알아서 이미지를 새로 만들고 서비스를 재시작합니다
docker-compose up -d --build [서비스_이름]
3. Dockerfile-dev도 중요
개발용 이미지를 담당하는 Dockerfile-dev 파일과 배포용 이미지를 담당하는 Dockerfile 파일이 따로 존재한다는 점을 꼭 기억해야 합니다. 간혹 Dockerfile만 고치면서 개발 환경에서 ‘외않돼?’라고 생각한 경우가 있습니다.
4. 데이터베이스 내용도 지우고 싶을 때
docker-compose down --volume : 깔끔하게 초기화 된다.
# Dockfile-dev에 관하여(불필요한 운영환경설정 명령어 생략)
FROM python:3
RUN apt-get update && apt-get -y install \
libpq-dev
WORKDIR /app
ADD ./requirements.txt /app/
RUN pip install -r requirements.txt
# ADD ./djangosample /app/djangosample/
// 해당 명령어 때문에, 로컬 프로젝트 소스 폴더와 컨테이너 내 소스폴더의 격리가 시작되는 것!(개발 중에는 필요 없음)
# ADD ./manage.py /app/
# CMD ["python", "manage.py", "runserver", "0:8000"]
// CMD: 도커 컴포즈의 command 속성으로 관리하는 편이 더 쉽기 때문에 생략
# 영구 db 저장소를 로컬에 맡기지 않고, Docker에 맡기기
1. Docker 볼륨을 생성한다.
볼륨은 도커가 관리하는 가상 디스크라고 생각
2. db 서비스 선언부 안에 volumes 항목을 넣고
- 가상디스크_이름 : 컨테이너_속_디렉터리처럼 지정
3. 이후로는 모든 데이터베이스 데이터가 django_sample_db_dev 볼륨에 저장됨
version: '3' # 변경 부분! volumes: //Docker 가상 디스크 생성 django_sample_db_dev: {} services: db: image: postgres volumes: # 여기도! - django_sample_db_dev:/var/lib/postgresql/data // 가상 디스크로 마운트 environment: ...
docker volume rm django_sample_db_dev
# 디버깅
1. 앱 서버가 데이터베이스를 못찾는 경우
- 첫 실행시 데이터베이스가 실행된 후 초기화 전에 앱서버가 실행되서 발생
- 가장 간단한 해결 방법은 서비스를 중지하고 다시 실행하는 것이지만 근본적인 해결책은 아님
- 이를 위해 wait-for-it.sh이라는 셸 스크립트를 사용
- 이 스크립트를 도커 이미지 안에 넣고, 이미지 실행 명령 앞에 붙여주면 됩니다.
./compose/django/Dockerfile-dev 파일의 마지막 부분에 다음 내용을 추가
ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh /
- docker-compose.yml 내 수정
services:
django:
command:
- bash
- -c
- |
/wait-for-it.sh db:5432 -t 10 // db 서비스의 5432 포트가 사용 가능할 때까지 기다린 후 앱 서버 실행
python manage.py runserver 0:8000
# 출처
https://www.44bits.io/ko/post/almost-perfect-development-environment-with-docker-and-docker-compose#%EB%8F%84%EC%BB%A4%EA%B0%80-%EB%B3%84%EB%A1%9C-%ED%8E%B8%ED%95%98%EC%A7%84-%EC%95%8A%EB%84%A4%EC%9A%94
'[CDS] DevOps > Docker' 카테고리의 다른 글
[Docker ] Docker 실습 (0) | 2022.05.04 |
---|---|
Docker 명령어 핵심만 이해하기 (0) | 2020.11.26 |
[Docker] Docker 이론 (0) | 2020.11.23 |
최근댓글