-
Notifications
You must be signed in to change notification settings - Fork 2
Docker and Kubernetes
pp edited this page Jul 20, 2024
·
18 revisions
아키텍쳐 그리던 도중에 도커랑 쿠버네티스 관련으로 간단하게 공부하면서 내용 공유해봅니다.
혹시 잘못되거나 추가되었으면 좋겠다 하는 부분이 있으면 자유롭게 수정해주시면 감사하겠습니다 !
가상화 기술을 기반으로 격리된 컨테이너를 만들어 어플리케이션을 실행할 수 있는 오픈소스 플랫폼.
사용자의 OS환경과 별개로 격리된 환경을 제공한다는 점에서 가상 머신(Virtual Machine)과 비슷하다고 생각할 수도 있지만
VM은 환경 생성 시 Guest OS까지 설치해야 해서 설치 및 실행에 많은 컴퓨팅 자원이 필요한 반면
Docker 컨테이너는 커널을 제외한 나머지 부분만을 가지고 실행되기 때문에 빠르고 가볍게 격리 환경을 만들어 낼 수 있음
-
이식성 : 실행 환경을 가리지 않고, 개발 환경, 테스트 환경, 배포 환경에서 동일한 어플리케이션을 실행 가능.
한 번 구축, 어디서나 실행
- 효율적인 리소스 사용 : 하나의 서버에서 컨테이너 환경을 사용하여 여러 어플리케이션을 사용하게됨으로 서버 자원을 효율적으로 사용할 수 있다.
-
확장성 : 하나의 도커 이미지를 가지고 다수의 컨테이너를 빠르게 생성 가능 (
Scale out
이 쉽다) - 개발 환경 일치 : 동일한 docker image를 사용, 개발 환경을 통일시켜 일관된 개발 환경을 유지하게 해준다. ('내 pc에서는 잘 되던데?' 방지)
- 버전 관리 : 이미지가 tag를 통해 관리되며, 만약 배포한 이미지에 문제가 생겼을 경우 이전 버전 이미지로 빠른 재배포가 가능하다.
- 오픈소스 생태계 : 컨테이너 표준으로 사용되는 만큼 단단한 생태계가 구축되어 있음
- 핵심이 되는 키워드는
격리
,호환성
,편의성
이라고 이해함
- 컨테이너를 사용하는데 핵심이 되는 개념
독립된 환경
- 독립된 환경을 사용하는 이유?
-
사용하는 시스템 별로 필요 조건(다른 프로그램 혹은 의존성 등)이 다르다.
-
시스템 구동에 있어서 같은 프로그램 혹은 의존성을 공유하지만 필요한 버전이 다를 수 있다.
- App A와 App B가 모두 구동하는데 App C를 필요로 하지만, 필요로하는 버전이 다를 경우
- 1.0을 선택하면 B를 사용하지 못하고, 2.0을 선택하면 A를 사용하지 못한다.
- 이런 상황을 피하기위해 격리된 컨테이너에서 각자가 필요한 의존성을 확보하여 실행에 문제가 없게 할 수 있다.
-
- Docker 이외에도 LXC, Solaris Zones, BSD Jail 같은 컨테이너 기술들이 존재하지만, 이런 기술들은 특정 OS(Solaris, FreeBSD)에서만 동작하기 때문에
어느 OS에서든 사용할 수 있는 도커가 표준으로 채택되었다.
- 호환성과 마찬가지로 다른 컨테이너 플랫폼에 비해서 러닝커브가 낮아 쉽게 사용이 가능하고,
탄탄한 생태계를 바탕으로 많은 레퍼런스와 다양한 오픈 소스 및 상용 툴과의 통합을 지원한다(= 다양한 환경에서의 사용이 편하다).
도커 관련 기본적인 용어 정리
- Docker Image는 특정 시점의 어플리케이션/환경을 정의하는 R/O파일로서 어플리케이션 실행에 필요한 소스 코드, 라이브러리, 종속성 등을 포함하고 있다.
- 이미지는 읽기 전용 파일 이므로 변경이 불가능하고 이미지를 사용해 Container 생성시 R/W가 가능한 Container Layer를 만들어 쓰기 작업을 수행할 수 있다.
- Layer관련 참고 : 참고1 참고2
- Dockerfile 은 도커 이미지를 빌드하기 위한 설정 파일(스크립트)이다.
- Dockerfile 에 이미지 빌드를 위한 커맨드를 입력하면 build 시 파일에 기재된 순서대로 이미지를 빌드한다.
- Dockerfile 예시 (더 자세한 내용은 공식 문서나 참고 블로그를 살펴볼 것)
FROM openjdk:17-alpine
# redis 및 tzdata 설치
RUN apk add --no-cache redis tzdata
# 타임존 설정
ENV TZ=Asia/Seoul
RUN cp /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# JAR 파일 복사
COPY build/libs/*.jar app.jar
# JASYPT_KEY ARG 및 ENV 설정
ARG JASYPT_KEY
ENV JASYPT_KEY=$JASYPT_KEY
# 포트 노출 - 생성된 컨테이너에 열어줄 이미지를 정의
EXPOSE 8080
# 애플리케이션 실행 // ENTRYPOINT - 무조건적인 실행, CMD - 실행 시의 옵션에 따라 변경 가능
ENTRYPOINT ["java", "-jar", "/app.jar"]
- 컨테이너는 응용 프로그램이 서로 다른 컴퓨팅 환경에서 빠르고 안정적으로 실행되도록 코드와 모든 종속성을 패키지화하는 소프트웨어의 표준 단위이다.
- 소프트웨어를 주위 환경으로부터 격리하고 개발과 스테이징 간의 차이에도 불구하고 균일하게 작동하도록 보장
- 변경된 container를 가지고 새로운 이미지를 만들 수 있다 (commit 커맨드)
- 로컬 환경과 격리된 환경이기 때문에 로컬 테스트 환경에서 container에 접속하고자 할 때는 localhost가 아니라 실제 ip와 열어준 포트를 사용해서 접속해야 한다.
- Docker Image가 저장되는 저장소. Docker hub 가 대표적인 public registry 이고, AWS ECR(Elastic Container Registry)도 레지스트리이다.
- ECR vs Dokcer hub?
- AWS ECR의 가장 큰 장점은 IAM을 사용한 권한 관리. docker hub도 private/public 으로 제어가 가능하지만 세부적인 관리는 ECR이 우수하다.
- 타 AWS 서비스와도 연계가 잘 되어있다는 것도 ECR의 장점이라 볼 수 있다.
- 생성된 Docker container와 호스트 PC(또는 다른 Docker Container)간에 공유할 수 있는 저장 공간
- 컨테이너는 가상화 기술을 기반으로 격리된 환경이기 때문에 작업한 데이터가 기본적으로 컨테이너 내부에서만 존재한다.
- (= 컨테이너를 삭제하면 작업한 데이터도 같이 사라진다.)
- 컨테이너가 삭제되더라도 작업한
데이터를 유지
해서 다음 컨테이너 또는 호스트 OS와공유
하고 싶을 때 volume을 생성하여 마운트시킨다. - 참고 블로그
- 격리된 Docker container 간에 통신을 하기 위한 논리적 네트워크
- 참고 블로그
도커 사용에 있어서 기본이 되는 커맨드들만 간단히 정리.
이외에 필요한 커맨드가 있으면 공식 문서 또는 구글링을 통해서 찾자.
- build : Dockerfile 을 기반으로 도커 이미지를 생성한다.
docker build -t [image name:tag] [Dockerfile path]
-
push : 보유한 Docker image를 registry에 올린다.
default로 Docker hub로 이미지를 업로드하고, ECR 등의 타 registry로 이미지를 올리고 싶은 경우에는 별도의 설정(AWS CLI, ECR 로그인 등)이 필요하다.
docker push [image name:tag]
-
pull : registry에 등록된 image를 로컬 서버로 받아온다.
push와 마찬가지로 Docker hub외의 registry에서 이미지를 받아올 때는 별도의 설정 후에 pull한다.
tag를 사용해 버전을 명시하지 않을 경우latest
이미지를 받아온다.
docker pull [image name:tag]
- rmi : 로컬 환경에서 이미지를 삭제한다.
docker rmi [image name:tag]
- images : 로컬 환경에 보유중인 이미지 리스트를 조회한다.
docker images
-
run : Docker iamge를 사용해 컨테이너를 만든다.
만약 보유중인 image가 없다면 registry에서 이미지를 pull해서 실행한다.
docker run [option] [image name:tag]
// 주로 사용하는 옵션 조합
docker run -d --name [container name] [image name:tag]
-d: 백그라운드에서 실행한다.
--name: 컨테이너 이름을 지정한다.
// docker volume 마운트
// 마운트 시에는 [volume name]의 내용으로 [container inner path] 내용이 덮어씌워지니 주의할 것
docker run -d --name [container name] -v [volume name]:[container inner path] [image name:tag]
- ps : 현재 실행 중인 컨테이너 목록을 출력한다.
// 실행 중인 컨테이너 목록 출력
docker ps
// 모든 컨테이너(중지 상태를 포함) 목록 출력
docker ps -a
- start : 정지 상태인 컨테이너를 실행시킨다.
docker start [container name]
- stop : 실행 중인 컨테이너를 정지 시킨다.
docker stop [container name]
- restart : 컨테이너를 재실작한다.
docker restart [container name]
- logs : 컨테이너의 로그를 출력한다.
docker logs [container name]
- rm : 컨테이너를 삭제한다.
docker rm [container name]
- exec : 실행 중인 컨테이너에서 명령을 실행한다.
docker exec [option] [container name] [command]
// 자주 사용하는 조합
docker exec -it [container name] [/bin/bash | /bash]
- 실행 중인 컨테이너의 bash shell을 실행시키고 사용자에게 표시한다.
- create : 새로운 Docker Network를 생성한다.
docker network create [network name]
- connect : 네트워크에 container를 연결시킨다.
docker connect [network name] [container name]
- ls : 현재 존재하는 Docker Network 목록을 출력한다.
docker network ls
- inspect : 네트워크 세부 정보를 출력한다.
docker network inspect [network name]
- rm : 네트워크를 삭제한다.
docker network rm [network name]
volume 은 connect명령어가 없다. 컨테이너를 생성할 때 -v또는 --mount 옵션을 사용해서 마운트 시킬 것.
- create : 새로운 볼륨을 생성한다.
docker volume create [volume name]
- ls : 현재 존재하는 Docker volume 목록을 출력한다.
docker volume ls
- inspect : 볼륨 세부 정보를 출력한다.
docker volume inspect [volume name]
- rm : 볼륨을 삭제한다.
docker volume rm [volume name]
docker-compose는 여러 개의 도커 컨테이너를 한 번에 정의하여 생성/삭제하게 해주는 도구이다.
docker-compose.yml 파일을 통해 사용할 이미지와 네트워크, 볼륨 등을 정의하여 다수의 컨테이너를 간단하게 배포 가능하게 해준다.
- docker-compose.yml 파일을 정의한 뒤,
docker-compose -f [docker-compose.yml path] up [option]
명령어를 통해 사용한다.- 만약
-f [docker-compose.yml path]
옵션 없이 사용한다면 현재 디렉토리에 있는 docker-compose.yml파일을 사용하여 동작하며, 파일이 없을 경우 오류가 발생함
- 만약
- docker-compose.yml 파일의 이름은 변해서는 안되며, 하나의 폴더(디렉토리)에 하나의 docker-compose.yml 파일만이 존재해야한다.
- docker-compose.yml 파일 예시
- 기타 커맨드
-
docker compose down
: docker-compose.yml에 정의된 컨테이너들을 정지하고 삭제시킨다. -
docker compose stop
: docker-compose.yml에 정의된 컨테이너들을 정지시킨다. -
docker compose start
: 파일에 정의되어있지만 정지 상태인 컨테이너들을 실행시킨다. up을 사용해도 무방함. -
docker compose ps
: 도커 컴포즈에 정의되어 실행 중인 컨테이너 목록을 출력한다.
-
- 이외의 커맨드나 옵션들에 대해서는 공식 문서나 구글링을 통해서 찾아보기
Kubernetese(k8s)는 컨테이너 오케스트레이션 도구로 다수의 컨테이너를 생성/삭제 해주고 컨테이너의 네트워크 및 관리를 자동화해주는 도구이다.
- k8s와 docker compose의 차이가 여기서 발생한다.
- docker compose는 다수의 컨테이너를 애드훅하게 생성/삭제 하는 반면
k8s는 etcd에 등록된 manifest file을 기준으로이상적인 상태
를 기억, 해당 상태를 유지할 수 있도록자동
으로관리
해준다. - 컨테이너의
배포
,제어 및 모니터링
,네트워킹
,스케일링
작업을 해결하기 위해 사용된다.
쿠버네티스 관련 기본적인 용어 정리
- 물리적 서버 또는 가상화 서버 환경을 의미.(그냥 app이 동작할 컴퓨터 하나라고 이해하자)
- k8s는 기본적으로 다수의 노드 간 컨테이너 오케스트레이션을 목적으로 사용된다.
- k8s는 두 종류의 노드를 가진다 : 1) Master Node 2) Worker Node
- Master Node :
Control Plane
이라고도 부르며 k8s 클러스터의 상태를 관리하고 조정하는 모든 컴포넌트를 포함하고 있다.
Worker Node와 달리 사용자가 직접적으로 접근할 일은 없고kubectl
등의 명령어를 통해 클러스터를 관리한다.
\- 컨트롤 플레인의 컴포넌트 :
kube-apiserver
,kube-controller-manager
,kube-scheduler
,cloud-controller-manager
,etcd
- kube-apiserver : 외부와 통신하는 프로세스, kubectl로부터 명령을 전달받아 실행한다.
-
kube-controller-manager : 컨트롤러를 통합 관리, 실행한다.
-
controller
: 클러스터의 최적의 상태를 유지하기 위해 지속적으로 상태를 감시하고 이를 조정하는 역할을 하는 소프트웨어 루프
-
- kube-scheduler : 파드를 워커 노드에 할당한다.
- cloud-controller-manager : 클라우드 서비스와 연동해 서비스를 생성한다.
- etcd : 클러스터 관련 정보 전반을 관리하는 데이터베이스.
-
EKS
: AWS 환경에서 k8s클러스터를 관리해주는 일종의 Control Plane 역할을 하는 서비스이다.
- 컨트롤 플레인의 컴포넌트 :
- Worker Node : 실제 애플리케이션 워크로드가 실행되는 노드. 컨테이너화된 애플리케이션을 실행하는 주체이다.
- Worker node의 컴포넌트 :
kubelet
,kube-proxy
-
- kubelet : 마스터 노드에 있는 kube-scheduler와 연동하며 워커 노드에 파드를 배치하고 실행한다. 또 실행 중인 파드의 상태를 정기적으로 모니터링하며 kube-scheduler에 통지한다.
-
- kube-proxy : 네트워크 통신의 라우팅 메커니즘. 파드 간의 통신 및 로드 밸런싱을 담당한다.
-
- Worker node의 컴포넌트 :
- Master Node(Control Plane)와 Worker Node로 구성된 환경을 우리는 Kubernetes Cluster라고 부른다.
- Kubernetes에서 배포되고 관리되는 가장 작은 단위.
하나 이상의 컨테이너 + 볼륨 조합
을 파드라 한다.
- 다수의 파드를 이끄는 반장 역할이라고 이해.
- 여러 Pod에 대한 단일 진입점을 제공하며, 이를 통해 로드 밸런싱과 서비스 디스커버리를 수행한다.
- 하나의 서비스 아래에는 동일한 구성(동일한 이미지의 컨테이너 + 볼륨)의 파드들이 존재한다.
- 구성이 다른 파드는 별개의 서비스로 관리한다.
-
로드 밸런서
역할. 각 서비스는 자동적으로 고정된 IP주소(cluster ip) 를 부여 받으며, 이 주소로 들어오는 통신을 각 파드에 분배해서 처리한다. - 내부적으로는 여러 개의 파드가 있어도 밖에서는 하나의 IP 주소(cluster IP)만 볼 수 있으며,
이 주소로 접근하면 서비스가 통신을 적절히 분배해주는 구조다. - 서비스가 분배하는 통신은 동일한 구성의 파드로 국한된다. 여러 서비스 노드 간의 분배는 상위 단에서 로드 밸런서나 Ingress가 담당함.
- LB나 Ingress는 물리적 하드웨어이거나 master/worker node와 다른 node에서 동작하게 된다.
- 서비스가 요청을 배분하는 반장이라면 레플리카셋은
파드의 수를 관리
하는 반장. - 장애 등의 이유로 파드가 종료됐을 때, 모자라는 파드를 보충하거나 정의 파일에 정의된 파드의 수가 감소하면 그만큼 파드의 수를 실제로 감소시킨다.
-
Replica
: ReplicaSet이 관리하는 동일한 구성의 파드를 의미한다.
- Manifest file은
Kubernetes 리소스를 정의
하는 YAML 또는 JSON 형식의 파일. - docker-compose.yml 과 다르게 파일명에 제약은 없지만 의미없는 이름을 붙이지 않도록 한다. (컨벤션 준수)
- k8s는 매니페스트 파일(정의 파일)에 기재된 내용에 따라 파드를 생성하고 관리한다.
- 매니페스트 파일의 내용을 쿠버네티스에 업로드하면 그 내용이 데이터베이스(etcd)에 등록되며, 클러스터 환경을 이 상태로 유지한다.
- 매니페스트 파일은 리소스(Pod, Deployment, Service, ReplicaSet...) 별로 따로 작성해줘야 하며 각각의 리소스 별로 별도의 파일을 만들거나
하나의 파일에서 구분선 (---)을 사용하여 여러 리소스의 설정을 하나의 파일로 정의할 수 있다. - 매니페스트 파일 주 항목 :
apiVersion:
kind:
metadata:
spec:
/*
1) apiVersion : API 그룹 및 버전, 그룹이나 버전은 변경될 수있으므로 공식 참조문서의 리소스 유형을 참조해서 만든다.
2) kind : 리소스 유형(Deployment, Service, Pod, ReplicaSet..주로 사용하는 리소스는 Deployment와 Service이다)
3) metadata: 메타 데이터 (리소스의 이름이나 레이블등의 메타 데이터)
4) spec: 리소스 내용. 어떤 리소스를 만들것인가? 스펙에서 정의하는 항목은 리소스 유형에 따라 달라지므로 따로 정리할 것
*/
- Deployment Manifest file 기본 구조
어디까지나 기본이니 추가로 필요한 부분은 공식 문서나 구글링을 참고하자.
apiVeresion:
kind:
metadata:
name: (등록할 Deployment의 이름)
spec:
selector:
matchLabels: (셀렉터가 관리할 라벨 이름)
replicas: (레플리카 설정 - 파드를 몇개 유지할 것인지)
template: (Pod의 정보)
metadata: (Pod의 이름, 라벨 단, Pod를 여러 개 관리할 경우 이름은 거의 사용하지 않는다.)
labels:
app: (Pod의 라벨 - 위의 selector를 사용해서 라벨이 붙은 파드들을 관리할 수 있다.)
spec: (Pod의 스펙)
containers:
- name: (컨테이너 이름)
image: (컨테이너를 만들때 사용할 이미지)
ports:
- containerPort: (컨테이너 내부에서 어떤 포트를 사용하고 있는지 정보)
/*
Deployment manifest file에서 지정하는 containerPort 는 단순히 정보를 제공하는 역할이며
주로 사람이 이해하기 쉽게 도와주는 역할을 한다. 실제 포트포워딩에 관련된 설정은
Service manifest file에서 지정하게된다.
*/
- Service Manifest file 기본 구조
apiVersion:
kind: Service
metadata:
name: (서비스 이름)
spec:
type: (서비스 유형 - 서비스의 종류를 말한다. 외부로부터 서비스에 어떤 유형의 IP 주소(또는 DNS)로 접근할지를 설정
ports: 포트 설정
- port: (서비스 포트)
- targetPort: (컨테이너 포트)
- protocol : (통신에 사용하는 프로토콜)
- nodePort: (Worker node의 포트)
selector: (셀렉터 설정)
/*
서비스 유형 :
1) ClusterIP : 클러스터 IP를 통해 서비스에 접근하도록 함(외부에서는 접근 안됨)
2) NodePort: 워커 노드의 IP를 통해 서비스에 접근하도록 함
3) LoadBalancer : 로드 밸런서의 IP를 통해 서비스에 접근하도록 함
4) ExternalName : 파드에서 서비스를 통해 외부로 나가기 위한 설정
*/
- 서비스 유형
쿠버네티스 사용에 있어서 기본이 되는 커맨드들만 간단히 정리.
이외에 필요한 커맨드가 있으면 공식 문서 또는 구글링을 통해서 찾자.
-
apply : manifest file을 사용하여 리소스를 생성하거나 업데이트한다.
주로-f
옵션과 함께 사용하여 특정 파일을 지정하여 사용하게 된다.
kubectl apply -f [manifest file path]
- get : 지정한 리소스 목록을 나열한다.
kubectl get nodes
kubectl get services
kubectl get deployments
kubectl get pods
- logs : Pod 의 로그를 출력한다.
kubectl logs [pod name]
- describe : 리소스의 상세 정보를 출력한다.
kubectl describe node [node name]
kubectl describe service [service name]
kubectl describe deployment [deployment name]
kubectl describe pod [pod name]
- rollout restart : registry에 새로운 이미지가 등록되었을 때 새로운 이미지로 pod를 재실행한다.
kubectl rollout restart deployments [deployment name]
- delete : 등록된 리소스를 제거한다.
kubectl delete pods [pod name]
kubectl delete deployments [deployment name]
kubectl delete services [service name]
docker exec -it --user root [container name] [/bin/bash 등..]
exec로 접근할 때 위 명령어로 접근하면 root로 exec접근이 됩니다.
이후 yum 등으로 필요한 패키지 다운로드 한 다음에 docker commit으로 새 이미지를 만들면 커스텀한 상태로 쓸 수 있습니다.
- 기본적인 참고 Docker document k8s document
- 🤝 Collaboration
- 💬 Git Commit Convention
- 🌿 Branching Strategy
- 🔀 Pull Request (PR) Guidelines
- 🐋 Docker
- 🎡 Kubernetes
- 🔎 Metrics
- 💊 USE/RED
- 📝 Metrics Design
- 🔥 Prometheus
- 🦖 Grafana
- ⚒️ 실제 구현