Docker & Kubernetes : 실전 가이드 필기 # Docker ## Docker 기본 개념 컨테이너 : 소프트웨어의 실행 단위 이미지 : 컨테이너를 위한 템플릿 / 청사진 단일 이미지로 여러 컨테이너를 띄울 수 있다. 모든 설정과 코드가 포함된 공유 가능한 패키지가 이미지이며 컨테이너는 해당 이미지의 구체적인 실행 인스턴스이다. 이미지 : Docker hub 등에서 공유받은 이미지를 사용 혹은 직접 만들 수 있다 ex) docker run node 실행시 공식 node 이미지를 다운받아서 바로 실행됨 docker run 실행시마다 새로운 인스턴스가 생성됨 Vscode의 docker extention은 유용하다. ## Dokcerfile 작성법 - FROM 으로 보통 시작, 대부분 운영 체제 레이어가 필요하기 때문 ( node 등) - COPY : 경로 두개를 인수로 받는다. 첫 번째 경로는 컨테이너 외부 경로, > ex) COPY . . 현재 Dockerfile이 있는 곳과 동일한 폴더와 그 하부 경로의 파일이 도커 컨테이너의 현재 작업 경로에 복사됨 세부 경로를 지정해 줄 경우 해당 경로에(혹은 생성된 경로에) 파일을 복사함 - RUN : 명령어 실행 - WORKDIR : 명령어들이 실행될 곳의 경로를 지정 - CMD : 동일 이미지에서 여러 인스턴스를 실행할 경우 쓰는 명령어 - 이미지가 생성될 때 실행되지 않고 이미지를 기반으로 한 컨테이너가 실행될 때 실행된다. - EXPOSE : 특정 포트를 개방하기 위해 사용 예시) `FROM node` 노드 이미지를 기반으로 `WORKDIR /app` 실행 경로는 /app `COPY . ./ ` 현재 도커파일 경로를 노드 이미지의 /app으로 복사 `RUN npm install` /app에서 npm install 실행 `EXPOSE 80` 80 포트 개방 (optional, 일종의 단순 선언문) `CMD [“node”, “server.js”]` node server.js 명령어 실행 ## 도커 콘솔 명령어 Build 명령어 파라미터 : docker build .(경로) Docker 실행 : docker run -p 3000:80(로컬 포트:내부 도커 노출 포트, 포트개방을 위해 필수) (name) Docker 컨테이너 중단 : docker stop (name) 이미지는 읽기 전용임, 내부 코드 수정시 이미지를 다시 빌드해야 된다. 이미지는 레이어기반임. Dockerfile의 각 명령어가 각자 다른 레이어로 취급된다. 각각의 레이어는 캐시되기 때문에 다시 빌드 할 경우 변경되지 않은 레이어는 빠르게 작업된다. 하나의 레이어가 수정되면 해당 레이어 이후의 명령어들은 모두 다시 실행된다. 도커 명령어에 —help를 붙이면 옵션 설명을 보여준다 중지된 컨테이너를 docker start로 재실행 할 수 있다. docker start는 detached 모드가 디폴트이고 docker run은 attached 모드가 디폴트이다 Attached 모드에서 도커 컨테이너를 실행시키면 콘솔 출력결과가 로컬 콘솔에도 표시된다. -d 옵션을 주면 detached로 실행된다 -a 옵션은 attached 모드로 실행 docker attach (name) 명령어로 실행중인 컨테이너에 수동으로 붙을 수 있다. docker logs 명령어로 지난 로그를 볼 수 있다. ## 도커 인터렉티브 -i 옵션을 이용해 인터렉티브 모드를 실행시킬 수 있다. -t 옵션은 유사 tty 모드를 실행시켜 터미널 통신을 가능하게 해준다. 결합해서 -it 옵션으로 실행시키면 터미널로 컨테이너에서 작동중인 프로그램과 터미널 통신을 할 수 있다. 단순 attached 모드에서는 상호작용이 안된다. Docker start 시에는 -a -i 옵션을 이용해 attached 모드에서 인터렉티브 모드를 실행해야 한다. ## 이미지 / 컨테이너 관리 docker ps 로 컨테이너 목록을 볼 수 있다. docker rm 으로 컨테이너 삭제가 가능 실행중인 컨테이너는 docker stop으로 중단 후 삭제 가능 rm은 띄어쓰기로 여러 컨테이너 id, 이름을 한번에 넘길 수 있다. docker images 로 이미지들 목록을 확인할 수 있다. docker image prune 으로 사용하지 않은 이미지를 삭제할 수 있다. docker rmi 로 이미지 개별 삭제가 가능하다. 다만 컨테이너가 있는 경우에는 삭제 불가 docker run 에 -rm 옵션을 주면 종료시 자동으로 컨테이너가 삭제된다. docker image inspect 명령어를 이용해 이미지 내부를 살펴볼 수 있다. 시간, 구성정보, entrypoint, 운영체제 버전 등등을 확인 할 수 있다. 이미지 내부의 레이어 수는 도커파일 명령어 수와 일치하지는 않는다. 베이스 이미지 내의 레이어를 가져오기 때문 ## 이미지 / 컨테이너 내부의 파일 관리 docker cp 로컬경로 컨테이너이름:내부경로 명령을 이용해 컨테이너 내부로 파일을 복사할 수 있다. 반대도 역시 가능 ## 태깅 & 네이밍 docker run 에 —name 옵션으로 컨테이너의 이름을 줄 수 있다. docker build 에 -t 옵션을 주면 태그가 부여된다. 태그는 name : tag 의 두 부분으로 나뉜다. name은 해당 이미지의 그룹화된 이름이고 tag로 특정 버전을 구별할 수 있다. ## 이미지 공유 도커파일을 공유하는 경우 도커파일 주변의 파일이나 설정도 필요한 경우가 있다. 때문에 보통 도커 이미지의 공유는 이미지 자체를 공유하는 경우가 많다. 도커 허브 또는 개인 레지스트리에서 도커 이미지를 관리할 수 있다. 도커 허브 무료 플랜으로도 대부분의 주요 기능을 쓸 수 있다. docker push/pull (이미지 이름) 명령어를 이용 docker hub 이용법은 깃헙과 비슷한듯 하며 홈페이지에 잘 설명되어있다. 이미지 이름 변경은 docker tag (이전이름) (새이름) 명령어를 통해 가능하다. docker login 명령어를 이용해 로컬 콘솔에서 docker hub에 로그인 할 수 있다. ## 데이터 관리 및 볼륨 데이터의 종류 : Application Data (코드+환경), 임시 앱 데이터(메모리 데이터), 영구 앱 데이터 이미지에 복사하면 코드나 환경등은 고정됨. 이 데이터는 변경할 필요가 없고 실행중에는 변경 되어서도 안됨 임시 앱 데이터는 가동중에만 쓰이고 종료 시 삭제 되어야 됨 컨테이너 내의 read-write layer에 저장됨 파일이나 데이터베이스에 저장되는 지속적인 데이터의 경우 볼륨에 저장됨 컨테이너 내부에는 별도의 저장 공간이 있다. 종료해도 삭제하지 않으면 사라지진 않음 코드를 업데이트하고 이미지를 새로 빌드해서 새 컨테이너를 만들면 같은 이미지 기반이라도 데이터는 사라짐 이런 경우 볼륨을 사용하면 됨 특정 로컬 경로를 컨테이너상의 특정 위치와 매핑시킬 수 있음 dockerfile에 VOLUME 명령어를 이용 > ex) VOLUME [ “/app/feedback” ] 도커의 외부 저장공간 관리는 크게 두 방법이 있음 volumes, bind mounts 볼륨은 다시 명명된 것(named volume)과 익명의 볼륨 두 가지가 있음 볼륨은 docker volume 커맨드로 관리할 수 있음 지속적인 데이터는 명명된 볼륨을 이용해야함 위에서 살펴본 dockerfile에 선언하면 익명의 볼륨이 생성됨 익명의 볼륨은 컨테이너 종료시 삭제가 됨 ( --rm 옵션으로 종료 시) 익명 볼륨 수동 삭제는 docker volume rm || docker volume prune 으로 가능 명명된 볼륨은 docker run -v 옵션으로 생성할 수 있음 > ex) docker run -v feedback:/app/feedback (이름:경로) 익명 볼륨은 지속적이진 않지만 컨테이너 밖 공간을 활용할 수 있도록 해주고 로컬데이터와의 충돌방지를 위해 쓸 수도 있다. ## 바인드 마운트 볼륨 옵셥을 줄 때 이름이 아니라 절대경로를 지정하면 로컬 머신의 경로와 도커 컨테이너 내의 경로를 매핑할 수 있다. (이 경우 큰따옴표로 묶어야 함, 또한 맥에서는 도커 설정에서 해당 경로가 공유되고 있는지를 확인해아 한다.) (-v $(pwd):app 과 같은 방식으로도 현재 경로를 지정해 줄 수 있다.) 이 경우 중복되는 파일이 있을 경우 로컬 파일이 컨테이너 내부 파일을 덮어쓰게됨 충돌을 방지하고 싶을 경우 -v옵션에서 :을 제거해 익명 볼륨을 추가할 수도 있다. 바인드 마운트에 :ro 를 추가하면 읽기 전용이 된다. 그냥도 바인드마운트는 로컬 파일을 변경할 수는 없음. 그래서 익명 볼륨을 같이 쓰는 경우들이 있다. 이미지에 COPY명령어가 있고 바인드 마운트를 같이 쓰면 작동은 하지만 COPY는 배포시에만 적용된다. ### Node tip devDependencies 에 nodemon을 추가하면 노드 프로젝트를 재실행하지 않아도 변경사항이 바로 반영된다. 이 경우 실행 명령어가 nodemon server.js 와 같은 방식으로 수정되어야 한다. ## 도커 볼륨 관리 docker volume create : 볼륨을 생성해 쓸 수 있다. docker volume ls : 볼륨 목록 조회 docker volume rm || docker volume prune : 도커 볼륨 삭제 docker volume inspect : 볼륨 설정 확인 (mountpoint : 컨테이너 내부에서 연결된 경로) ## dockerignore .dockerignore 파일을 통해 .gitignore 처럼 사용할 수 있다. node_modules 같은 디렉토리는 어처피 이미지 생성시에 따로 만들어지기 때문에 이그노어 파일에 추가해놓을만 하다. .git폴더도 ignore에 추가할만 하다. ## 환경변수 전역적으로 사용할 수 있는 환경변수가 있음 (process.env) 도커파일에 ENV 라는 이름으로 선언 가능 > ex) ENV PORT 80 > EXPOSE $PORT 이미지 생성시에 default 값을 설정할 수 있지만 실행 명령어에서 파라미터로 주는 것도 가능하다 > ex) docker run —env(-e) PORT=8000 .env 파일을 만들어서 PORT=8000 같은 방식으로 키-값 을 넣고 —env-file ./.env 와 같이 옵션을 줘도 된다 ## 빌드 인수 ARG DEFAULT_PORT=80 도커파일에서만 사용할 수 있는 변수이다. CMD에서도 사용불가. ENV PORT $DEFAULT_PORT 같은 방식으로 쓸 수 있다. docker build —build-arg DEFAULT_PORT=8000 과 같이 이미지 빌드 시에 변수를 동적으로 지정할 수 있다. ## 네트워크 통신 통신 케이스 1. 컨테이너에서 외부 api와 통신 2. 컨테이너와 로컬 호스트 머신의 통신 3. 컨테이너 간 통신 컨테이너에서 외부 api 호출은 특별한 설정을 하지 않아도 바로 작동한다. ## 호스트 머신에 연결하기 host.docker.internal 도메인을 localhost 대신에 사용해야 한다. ## 컨테이너 간 통신 docker inspect container 로 네트워크 세팅의 ip를 찾을 수 있음 해당 Ip로 연결을 시도하면 컨테이너 간 통신이 가능하다 ## Docker networks --network (이름) 옵션으로 네트워크 명을 설정할 수 있다. docker network create (이름) 명령으로 도커 네트워크를 만들 수 있다 네트워크 생성 시 --driver 옵션을 이용해서 기본 bridge 드라이버 이외에 다른 드라이버를 설정할 수 있다. docker network ls 로 목록 조회 가능 동일한 네트워크 안에 있는 컨테이너들 간에는 컨테이너 이름으로 통신이 가능하다 > ex) mongodb://mongodb:27017 이렇게 쓸 경우 docker run —network 이름 옵션을 같은걸 줘야함 도커 네트워크 내부에서만 쓸 경우 -p 옵션을 안 줘도 된다. 요청이 컨테이너 내부에서 일어났을 때만 주소가 자동적으로 변환된다. ## SPA 도커화 리액트의 경우 실행시킬 때 -it 옵션을 안주면 서버가 실행되지 않음 ## Docker-Compose 도커 컴포즈 : docker build & run 명령을 대체할 수 있는 도구 이미지를 만들고 실행시켜주는 명령어 셋 도커 명령을 설정 파일에 저장 할 수 있게 되어 편리하다. ## docker-compose.yaml 파일 yaml 파일이므로 들여쓰기를 신경써야 한다. detached 모드와 --rm 옵션은 기본이다. docker-compose up : 도커 컴포즈 파일 실행 명령어 --build 옵션을 주면 이미지 재생성을 강제한다. docker-compose build : 실행은 안시키고 빌드만 원하는 경우 docker-compose down : 도커 컴포즈 중지 모든 컨테이너를 중지하고 제거한다. -v 옵션을 주면 볼륨도 삭제된다. 구성 예시 ) ``` version: “3.8” # 도커 컴포즈 버전 지정 services: # 컨테이너의 수 만큼 항목을 가진다. mongodb: container_name: ‘mongo’ # 컨테이너 네임을 별도로 지정할 수 있다. 안해도 됨 image: ‘mongo’ # 이미지 명 volumes: - data:/data/db environment: # 환경변수는 아래 두 양식이 모두 가능하다 - MONGO_INITDB_ROOT_USERNAME=max MONGO_INTDB_ROOT_PASSWORD: secret env_file: # 환경변수의 경우 아래와 같이 별도의 파일에서도 불러올 수 있다. - ./env/mongo.env networks: # 지정할 수도 있지만 동일한 도커 컴포즈 파일 내의 컨테이너는 자동으로 같은 네트워크에 소속된다. - goals-net backend: build: ./backend # dockerfile을 찾아 빌드하도록 할 수 있다. context: ./backend # 상세하게 속성을 명시 할 수도 있다. dockerfile: Dockerfile args: some-arg: 1 ports: - ’80:80’ volumes: - logs:/app/logs - ./backend:/app # 도커 컴포즈에서는 바인드 마운트 사용 시 상대경로를 쓸 수 있다. - /app/node_modules env_file: - ./env/mongo.env depend_on: # 선행되어야 되는 서비스 목록을 지정 - mongodb frontend: build: ./frontend port: - ‘3000:3000’ volumes: - ./frontend/src:/app/src stdin_open: true # i옵션 tty: true # t옵션 depend_on: - backend volumes: # 명명된 볼륨의 경우 여기에서 선언이 필요하다. 같은 이름의 볼륨은 다른 컨테이너에서 공유될 수 있다. data: logs: ``` ## 유틸리티 컨테이너 유틸리티 컨테이너 : 앱이 아닌 특정 환경만 포함한 컨테이너 노드 등의 특정 환경을 글로벌 설치 없이 쓸 수 있도록 해준다. 특별히 만드는 법이 따로 있지는 않고 이미지 구성 시 앱 부분만 빼면 된다. 보통 컨테이너와 바인드마운트를 이용해 로컬 환경에 프로젝트 셋업 등을 할때 사용되곤 한다. docker exec : 도커 컨테이너 내에 추가적인 명령을 내릴 수 있는 명령어 > ex) docker -it exec sample_container npm init ENTRYPOINT : docker run 명령어 뒤에 추가하는 명령어가 엔트리포인트에 붙어서 실행된다. > ex) ENTRYPOINT [“npm”] > docker-compose로 구성 시 docker-compose up 대신에 run 을 사용해야 한다. > ex) docker-compose run --rm npm init # 쿠버네티스 ## 쿠버네티스 개념 쿠버네티스는 도커 배포를 위한 추가 도구 쿠버네티스 구문은 클라우드 제공자를 가리지 않고 사용할 수 있다. 특화된 구성의 경우 별도로 빼서 따로 관리해 줄 수 있음 쿠버네티스의 핵심 : 배포를 표준화 시킨다. 쿠버네티스는 여러 머신을 위한 도커 컴포즈라고 생각해도 된다. ## 쿠버네티스 구조 워커노드 : 한 대의 컴퓨터나 가상 머신 단위라고 생각 할 수 있음. 이 안에 하나의 도커컴포즈 단위와 비슷한 포드들로 구성 ![](https://i.imgur.com/8K8fdiX.png) 마스터노드 : 워커 노드들을 관리 ![](https://i.imgur.com/un6ulDU.png) 전체 아키텍쳐 ![](https://i.imgur.com/KAdZ94U.png)