도커/쿠버네티스 컨테이너 개발 실전 입문 · · 6 min read
부록 B : 도커로 개발을 지원하는 도구 및 서비스
1. 인하우스 도커 레지스트리 구축
- 도커 이미지를 보관하기에는 도커 허브나 Quay.io 같은 퍼블릭 레지스트리 서비스를 이용하는 것이 편리하다.
- 퍼블릭 레지스트리를 사용 불가한 경우
- 퍼블릭 레지스트리의 지나치게 긴 응답 시간
- 보안 측면의 문제
- 운영 환경에 배포하기 위해 개발한 어플리케이션 이미지를 퍼블릭 레지스트리에 저장할 수는 없다.
- 인하우스 도커 레지스트리
- 레지스트리를 직접 구축하여 어떤 보안 정책이라도 만족시킬 수 있다.
- 컨테이너를 배포하는 호스트와 가까이 도커 레지스트리가 위치할 것이므로 배포 속도 또한 개선할 수 있다.
- Registry(Docker Distribution)
- 도커에서 인하우스 도커 레지스트리를 구축할 수 있도록 배포하는 도구
- Docker Distribution과 함께 제공된다.
- 오픈소스 소프트웨어이며 도커 컨테이너 형태로 실행할 수 있으므로 도커 호스트 역할을 할 운영 체제만 있으면 레지스트리 운영이 가능하다.
- 3장의 docker swarm을 구축할 때 사용했다.
- 구축
- Registry 설치(서버) : ubuntu 16.x
- /etc/systemd/system/docker-container@registry.service
[Unit] Descriptioni=Registry Requires=docker.service After=docker.service [Service] Restart=always ExecStart=/usr/bin/docker container run --rm --name registry -p 5000:5000 library/registry [Install] WantedBy=multi-user.target - 서비스로 활성화 한다.
$ systemctl enable docker-container@registry.service $ systemctl start docker-container@registry.service - 곧 registry 컨테이너가 실행된다.
- /etc/systemd/system/docker-container@registry.service
- Registry에 이미지 등록하기
- Registry는 HTTP API를 제공한다.
$ curl http://localhost:5000/v2/_catalog - 태그를 부여해 기존 알파인 리눅스 이미지를 Registry에 등록한다.
$ docker image pull alpine:3.7 $ docker image tag alpine:3.7 localhost:5000/alpine:3.7 $ docker image push localhost:5000/alpine:3.7
- Registry는 HTTP API를 제공한다.
- Registry에서 이미지 내려받기
- Registry 컨테이너를 실행한 호스트에서 localhost:5000으로 접근하면 된다.
- 그 외 호스트에서 Registry에서 접근하려면 도메인 부분을 다른 호스트에서 참조 가능한 IP 주소나 호스트명으로 바꿔야 한다.
- docker image pull 명령은 기본적으로 HTTPS를 통해 레지스트리에 접근하기 때문에 Registry 역시 HTTPS를 활성화 하지 않으면 오류가 발생한다.
- 외부에서 접근이 불가능한 내부 네트워크 안에서만 이미지가 전송된다면 굳이 HTTPS를 적용할 필요가 없다.
- docker image pull 명령을 실행하는 쪽의 /etc/docker/daemon.json 파일에 HTTP 통신을 허용한다.
Insecure registries에 값을 추가한다.
- Registry 설치(서버) : ubuntu 16.x
2. 도커와 CI/CD 서비스 연동
- 도커를 사용한 어플리케이션 개발 과정
- 구현 - 단위 테스트 - 어플리케이션 빌드 - 도커 이미지 빌드 - 도커 레지스트리 등록
- 위 과정의 반복
- 이 과정을 수작업으로 진행하면 실수가 발생하기 쉽다.
- CI/CD 서비스에 이 과정을 맡기면 실수를 줄이고 시간도 적야할 수 있으므로 적절한 자동화 도입이 매우 중요하다.
- CI : Continuous Integrate : 지속적 통합
- CD : Continuous (Deploy | Delivery) : 지속적 배포
- CI/CD 서비스의 예시 : Jenkins, CircleCI
- CircleCI
- INTRO
- SaaS(Software As A Service) 형태로 제공되는 CI/CD 서비스
- 빌드 설정 역시 yaml 포맷으로 기술할 수 있다.
- 이번에 다루는 내용은 CircleCI와 github를 사용한다.
- github 계정으로 OAuth 인증을 거쳐 가입하고 로그인한다.
- 프로젝트 추가
- github에 리포지토리를 새로 추가하고 내용으로 Dockerfile과 main.py를 생성한다.
- Dockerfile
FROM python:3.6-alpine WORKDIR /app COPY main.py /app/main.py CMD ["python", "main.py"] - main.py
# -*- coding: utf-8 -*- import socket # simple-echo-server def serve(host='0.0.0.0', port=8080): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((host, port)) s.listen() while True: conn, addr = s.accept() with conn: print('connected by', addr) if conn.recv(1024): conn.sendall(b'hello python!!') if __name__ == '__main__': serve()
- Dockerfile
- 프로젝트가 추가되면 대상 저장소에 푸시가 일어날 때마다 웹훅이 CircleCI의 CI/CD 잡을 시작하게 한다.
- 깃허브 조직 저장소를 추가하려면 깃 허브 설정에서 CircleCI의 Organization access 권한을 부여해야 한다.
- github에 리포지토리를 새로 추가하고 내용으로 Dockerfile과 main.py를 생성한다.
- 빌드 설정 파일 작성
- python 저장소를 이용해 도커 이미지 빌드에 이르는 과정을 설정한다.
- .circleci/config.yml
version: 2.1 jobs: build: # CircleCI 컨테이너의 작업 디렉토리 working_directory: /app # 잡을 실행하는 컨테이너의 도커 이미지 docker: - image: python:3.6-alpine steps: - checkout # 저장소에서 소스코드를 체크아웃 - persist_to_workspace: # workspace를 후속 잡에서 사용할 수 있도록 유지 root: . paths: - . docker_build_push: working_directory: /app docker: - image: docker:18.05.0-ce-dind # docker 명령을 사용할 수 있는 컨테이너 steps: - attach_workspace: # 저장해둔 workspace를 배치 at: . - setup_remote_docker: # docker image build를 수행할 데몬 준비 version: 18.05.0-ce - run: # 도커 이미지 빌드 name: docker image build command: docker image build -t joonstudydocker/echo-python:latest . - run: # 빌드된 이미지 확인 name : docker image ls command: docker image ls - run: # 도커 허브 로그인 name: docker login command: docker login -u $DOCKER_USER -p $DOCKER_PASS # 프로젝트 설정에서 환경 변수를 저장할 수 있다. - run: # latest 이미지를 도커 허브에 등록 name: release latest command: docker image push joonstudydocker/echo-python:latest workflows: version: 2 build_and_push: jobs: # workflows로 실행할 잡을 열거 - build - docker_build_push: requires: # build 잡 다음에 실행 - build # master 브랜치인 경우에만 실행 # 다른 브랜치에서도 실행하려면 주석 처리하거나 제거 filters: branches: only: master
- CircleCI와 저장소를 연동하여 어플리케이션 테스트 및 도커 이미지 빌드와 등록을 대신해주는 CI/CD 환경을 구축하였다.
- 참고
- docker login 오류 - ubuntu16.x
$ sudo apt install gnupg2 pass $ gpg2 --full-generate-key $ gpg2 -k $ pass init "whatever key id you have"
- docker login 오류 - ubuntu16.x
- INTRO
3. ECS에서 AWS Fargate를 이용한 컨테이너 오케스트레이션
- ECS - Elastic Container Service
- AWS는 지금까지 독자적인 컨테이너 오케스트레이션 서비스 ECS를 제공해왔다.
- ESC는 서버 여러대를 이용해 컨테이너 오케스트레이션을 구현하는 방식이다.
- ALB라는 AWS 서비스와 매끄럽게 연동된다.
- ALB - Application Load Balancer
- ECS는 최초 도입이 쿠버네티스보다 쉽기 때문에 프로젝트 규모와 무관하게 널리 사용된다.
- 넷플릭스에서 대규모로 운영한 실적이 있다.
- AWS Fargate
- 개발자가 서버나 클러스터를 직접 관리하지 않고 컨테이너를 실행하는 기술
- ECS나 EKS에서는 서버관리, 클러스터 프로비저닝 등을 담당하는 서비스이다.
- 컨테이너 오케스트레이션부터 서버 및 클러스터 관리에 이르기까지 가장 손이 많이 가는 작업을 제거했다는 점에서 획기적이라 할 수 있다.
- AWS Fargate는 AWS Lambda의 뒤를 잇는 차세대 서버리스 기술로서도 주목받고 있다.
- Lambda는 장시간 실행되는 배치 어플리케이션에는 적합하지 않은데, ECS는 이러한 약점을 보완할 수 있다.
- AWS Fargate는 서버 인스턴스를 신경 쓰지 않고도 간단히 컨테이너 오케스트레이션을 실현할 수 있으므로 컨테이너 기술 및 서버리스 기술 양쪽에서 새로운 트랜드가 될 것이다.
- Fargate로 ECS 클러스터 구축
- AWS console에서 ECS를 선택하면 Fargate 마법사 화면이 나타난다.
- 시작을 눌러서 설정을 시작한다.
- 1단계 : 컨테이너 및 작업
- nginx를 선택한다.
- 2단계 : 서비스
- 로드 밸런서 유형을 Application Load Balancer를 선택한다.
- 3단계 : 클러스터
- Cluster 이름을 설정한다.
- 필자는 joon으로 하겠다.
- 4단계 : 검토
- 지금까지의 내용을 검토한 뒤에 생성을 누른다.
- 생성 뒤 확인
- ECS 관련 리소스가 수 분 만에 생성된다.
- 생성된 nginx에 접속
- 생성한 뒤 로드 밸러서를 확인한다.
- ECS 클러스터에 배포된 컨테이너는 모두 ALB라는 로드 밸런서를 통해 접근하므로 지금 만든 ALB의 DNS name을 복사한다.
- 웹 브라우저에서 ‘http://복사한도메인’에 접근하면 nginx의 welcome 화면을 볼 수 있다.
- ECS를 조작해 어플리케이션 배포하기
- ECS 리소스
- (작음) Container Definition - Task Definition - Service - Cluster (큼)
- Container Definition : 배포되는 각 컨테이너의 정의
- Task Definition : 컨테이너의 집합인 Task의 정의
- 쿠버네티스 파드의 개념이 두 단계로 나뉘어 있다고 생각하면 된다.
- Task Definition 생성
- 작업 정의 - 새로운 작업 정의 작성
- FARGATE를 선택하고 다음을 누른다.
- 테스크 정의 이름은 echo-task로 한다.
- 네트워크 모드는 awsvpc를 선택하여 내부 IP(private)만 부여한다.
- CPU 리소스
- memory : 0.5GB
- CPU : 0.25vCPU
- 컨테이너 정의
- echo
- 이름 : echo
- 이미지 : stormcat24/echo:latest
- 포트 맵핑 : 8080
- nginx
- 이름 : nginx
- 이미지 : stormcat24/nginx-proxy:latest
- 포트 맵핑 : 80
- 환경변수
- BACKEND_HOST : value : localhost:8080
- echo
- 서비스 수정
- 새 배포 적용을 체크한다.
- 작업 개수는 1로 한다.
- 이후 화면은 수정 없이 다음을 클릭한다.
- Service 수정이 끝나면 이미 배포된 태스크가 정지되며 echo-task:1 태스크가 하나 배포된다.
- 태스크 상세 정보를 확인하면 echo와 nginx 컨테이너를 포함한 태스크가 배포된 것을 알 수 있다.
- ALB와 대상 그룹
- Service는 ABL와 연동해 외부로부터 접근할 수 있다.
- RUNNING 상태가 된 태스크는 ALB가 확인한 헬스 체크 결과가 healthy로 나와야 비로소 트래픽이 전달된다.
- ECS 리소스
- OUTRO
- 도커로 운영 환경을 꾸린다 해도 서버나 클러스터를 계속 신경써야 할 것이다.
- 그러나 Fargate를 사용하면 한 번 설정하면 그 이후에는 자동으로 제어된다.
- 이는 도커를 적용한 운영 환경을 쾌적하게 해주는 기술이다.