Skip to content

Docker and Kubernetes

pp edited this page Jul 20, 2024 · 18 revisions
아키텍쳐 그리던 도중에 도커랑 쿠버네티스 관련으로 간단하게 공부하면서 내용 공유해봅니다. 
혹시 잘못되거나 추가되었으면 좋겠다 하는 부분이 있으면 자유롭게 수정해주시면 감사하겠습니다 !

🐳 Docker

1. 개요

가상화 기술을 기반으로 격리된 컨테이너를 만들어 어플리케이션을 실행할 수 있는 오픈소스 플랫폼.
사용자의 OS환경과 별개로 격리된 환경을 제공한다는 점에서 가상 머신(Virtual Machine)과 비슷하다고 생각할 수도 있지만 
VM은 환경 생성 시 Guest OS까지 설치해야 해서 설치 및 실행에 많은 컴퓨팅 자원이 필요한 반면 
Docker 컨테이너는 커널을 제외한 나머지 부분만을 가지고 실행되기 때문에 빠르고 가볍게 격리 환경을 만들어 낼 수 있음

image

사용 이유

  1. 이식성 : 실행 환경을 가리지 않고, 개발 환경, 테스트 환경, 배포 환경에서 동일한 어플리케이션을 실행 가능. 한 번 구축, 어디서나 실행
  2. 효율적인 리소스 사용 : 하나의 서버에서 컨테이너 환경을 사용하여 여러 어플리케이션을 사용하게됨으로 서버 자원을 효율적으로 사용할 수 있다.
  3. 확장성 : 하나의 도커 이미지를 가지고 다수의 컨테이너를 빠르게 생성 가능 (Scale out이 쉽다)
  4. 개발 환경 일치 : 동일한 docker image를 사용, 개발 환경을 통일시켜 일관된 개발 환경을 유지하게 해준다. ('내 pc에서는 잘 되던데?' 방지)
  5. 버전 관리 : 이미지가 tag를 통해 관리되며, 만약 배포한 이미지에 문제가 생겼을 경우 이전 버전 이미지로 빠른 재배포가 가능하다.
  6. 오픈소스 생태계 : 컨테이너 표준으로 사용되는 만큼 단단한 생태계가 구축되어 있음

2. 키워드

  • 핵심이 되는 키워드는 격리, 호환성, 편의성 이라고 이해함

1) 격리

  • 컨테이너를 사용하는데 핵심이 되는 개념 독립된 환경
  • 독립된 환경을 사용하는 이유?
    1. 사용하는 시스템 별로 필요 조건(다른 프로그램 혹은 의존성 등)이 다르다.

    2. 시스템 구동에 있어서 같은 프로그램 혹은 의존성을 공유하지만 필요한 버전이 다를 수 있다.
      image

    • App A와 App B가 모두 구동하는데 App C를 필요로 하지만, 필요로하는 버전이 다를 경우

      image
    • 1.0을 선택하면 B를 사용하지 못하고, 2.0을 선택하면 A를 사용하지 못한다.
      image
    • 이런 상황을 피하기위해 격리된 컨테이너에서 각자가 필요한 의존성을 확보하여 실행에 문제가 없게 할 수 있다.

2) 호환성

  • Docker 이외에도 LXC, Solaris Zones, BSD Jail 같은 컨테이너 기술들이 존재하지만, 이런 기술들은 특정 OS(Solaris, FreeBSD)에서만 동작하기 때문에
    어느 OS에서든 사용할 수 있는 도커가 표준으로 채택되었다.

3) 편의성

  • 호환성과 마찬가지로 다른 컨테이너 플랫폼에 비해서 러닝커브가 낮아 쉽게 사용이 가능하고,
    탄탄한 생태계를 바탕으로 많은 레퍼런스와 다양한 오픈 소스 및 상용 툴과의 통합을 지원한다(= 다양한 환경에서의 사용이 편하다).

3. 용어

도커 관련 기본적인 용어 정리

1) Docker Image

  • Docker Image는 특정 시점의 어플리케이션/환경을 정의하는 R/O파일로서 어플리케이션 실행에 필요한 소스 코드, 라이브러리, 종속성 등을 포함하고 있다.
  • 이미지는 읽기 전용 파일 이므로 변경이 불가능하고 이미지를 사용해 Container 생성시 R/W가 가능한 Container Layer를 만들어 쓰기 작업을 수행할 수 있다.
  • Layer관련 참고 : 참고1 참고2 docker.docs

2) Dockerfile

  • 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"]

3) Container

  • 컨테이너는 응용 프로그램이 서로 다른 컴퓨팅 환경에서 빠르고 안정적으로 실행되도록 코드와 모든 종속성을 패키지화하는 소프트웨어의 표준 단위이다.
  • 소프트웨어를 주위 환경으로부터 격리하고 개발과 스테이징 간의 차이에도 불구하고 균일하게 작동하도록 보장
  • 변경된 container를 가지고 새로운 이미지를 만들 수 있다 (commit 커맨드)
  • 로컬 환경과 격리된 환경이기 때문에 로컬 테스트 환경에서 container에 접속하고자 할 때는 localhost가 아니라 실제 ip와 열어준 포트를 사용해서 접속해야 한다.

4) Registry

  • 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의 장점이라 볼 수 있다.

5) Docker Volume

  • 생성된 Docker container와 호스트 PC(또는 다른 Docker Container)간에 공유할 수 있는 저장 공간
  • 컨테이너는 가상화 기술을 기반으로 격리된 환경이기 때문에 작업한 데이터가 기본적으로 컨테이너 내부에서만 존재한다.
  • (= 컨테이너를 삭제하면 작업한 데이터도 같이 사라진다.)
  • 컨테이너가 삭제되더라도 작업한 데이터를 유지해서 다음 컨테이너 또는 호스트 OS와 공유하고 싶을 때 volume을 생성하여 마운트시킨다.
  • 참고 블로그

6) Docker Network

  • 격리된 Docker container 간에 통신을 하기 위한 논리적 네트워크
  • 참고 블로그

4. 사용법

도커 사용에 있어서 기본이 되는 커맨드들만 간단히 정리.
이외에 필요한 커맨드가 있으면 공식 문서 또는 구글링을 통해서 찾자.

1) Image 관련 커맨드

  • 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

2) Container 관련 커맨드

  • 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을 실행시키고 사용자에게 표시한다.

3) Network 관련 커맨드

  • 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]

4) Volume 관련 커맨드

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

1. 개요

docker-compose는 여러 개의 도커 컨테이너를 한 번에 정의하여 생성/삭제하게 해주는 도구이다.
docker-compose.yml 파일을 통해 사용할 이미지와 네트워크, 볼륨 등을 정의하여 다수의 컨테이너를 간단하게 배포 가능하게 해준다.  

2. 사용법

  • 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 : 도커 컴포즈에 정의되어 실행 중인 컨테이너 목록을 출력한다.
  • 이외의 커맨드나 옵션들에 대해서는 공식 문서나 구글링을 통해서 찾아보기

맨 위로

🎡 Kubernetes

1. 개요

Kubernetese(k8s)는 컨테이너 오케스트레이션 도구로 다수의 컨테이너를 생성/삭제 해주고 컨테이너의 네트워크 및 관리를 자동화해주는 도구이다.

2. 키워드

1) Ochestration

  • k8s와 docker compose의 차이가 여기서 발생한다.
  • docker compose는 다수의 컨테이너를 애드훅하게 생성/삭제 하는 반면
    k8s는 etcd에 등록된 manifest file을 기준으로 이상적인 상태를 기억, 해당 상태를 유지할 수 있도록 자동으로 관리해준다.
  • 컨테이너의 배포, 제어 및 모니터링, 네트워킹, 스케일링 작업을 해결하기 위해 사용된다.

3. 용어

쿠버네티스 관련 기본적인 용어 정리

1) Node

  • 물리적 서버 또는 가상화 서버 환경을 의미.(그냥 app이 동작할 컴퓨터 하나라고 이해하자)
  • k8s는 기본적으로 다수의 노드 간 컨테이너 오케스트레이션을 목적으로 사용된다.
  • k8s는 두 종류의 노드를 가진다 : 1) Master Node 2) Worker Node

k8s cluster image

  • 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
        1. kubelet : 마스터 노드에 있는 kube-scheduler와 연동하며 워커 노드에 파드를 배치하고 실행한다. 또 실행 중인 파드의 상태를 정기적으로 모니터링하며 kube-scheduler에 통지한다.
        1. kube-proxy : 네트워크 통신의 라우팅 메커니즘. 파드 간의 통신 및 로드 밸런싱을 담당한다.

2) Cluster

  • Master Node(Control Plane)와 Worker Node로 구성된 환경을 우리는 Kubernetes Cluster라고 부른다.

3) Pod

  • Kubernetes에서 배포되고 관리되는 가장 작은 단위. 하나 이상의 컨테이너 + 볼륨 조합을 파드라 한다.

4) Service

  • 다수의 파드를 이끄는 반장 역할이라고 이해.
  • 여러 Pod에 대한 단일 진입점을 제공하며, 이를 통해 로드 밸런싱과 서비스 디스커버리를 수행한다.
  • 하나의 서비스 아래에는 동일한 구성(동일한 이미지의 컨테이너 + 볼륨)의 파드들이 존재한다.
  • 구성이 다른 파드는 별개의 서비스로 관리한다.
  • 로드 밸런서역할. 각 서비스는 자동적으로 고정된 IP주소(cluster ip) 를 부여 받으며, 이 주소로 들어오는 통신을 각 파드에 분배해서 처리한다.
  • 내부적으로는 여러 개의 파드가 있어도 밖에서는 하나의 IP 주소(cluster IP)만 볼 수 있으며,
    이 주소로 접근하면 서비스가 통신을 적절히 분배해주는 구조다.
  • 서비스가 분배하는 통신은 동일한 구성의 파드로 국한된다. 여러 서비스 노드 간의 분배는 상위 단에서 로드 밸런서나 Ingress가 담당함.
  • LB나 Ingress는 물리적 하드웨어이거나 master/worker node와 다른 node에서 동작하게 된다.

image

5) ReplicaSet

  • 서비스가 요청을 배분하는 반장이라면 레플리카셋은 파드의 수를 관리하는 반장.
  • 장애 등의 이유로 파드가 종료됐을 때, 모자라는 파드를 보충하거나 정의 파일에 정의된 파드의 수가 감소하면 그만큼 파드의 수를 실제로 감소시킨다.
  • Replica : ReplicaSet이 관리하는 동일한 구성의 파드를 의미한다.

6) Manifest file

  • 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 : 파드에서 서비스를 통해 외부로 나가기 위한 설정
*/
  • 서비스 유형 image

4. 사용법

쿠버네티스 사용에 있어서 기본이 되는 커맨드들만 간단히 정리.
이외에 필요한 커맨드가 있으면 공식 문서 또는 구글링을 통해서 찾자.

  • 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 & k8s 관련 시행착오

Docker Container root 권한

docker exec -it --user root [container name] [/bin/bash 등..] 

exec로 접근할 때 위 명령어로 접근하면 root로 exec접근이 됩니다.
이후 yum 등으로 필요한 패키지 다운로드 한 다음에 docker commit으로 새 이미지를 만들면 커스텀한 상태로 쓸 수 있습니다.


Clone this wiki locally