요약


도커 컴포즈는 다수의 컨테이너 어플리케이션을 정의하고(생성), 실행하는 툴을 의미한다. 이 도커 컴포즈는 간단히 하나의 텍스트파일(YAML 형식)을 작성해서, 여러개의 시스템을 실행하고, 종료, 폐기하여 컨테이너를 운용할 수 있는 툴이다[1]

이미지 소스: https://ostechnix.com/introduction-to-docker-compose/

 

Docker-compose vs Dockerfile vs 쿠버네티스


1. 도커 컴포즈(docker-compose)다수의 컨테이너의 실행(run), 정지(stop), 삭제(rm)을 한번해 실행 시킬 수 있는 명령어(툴)이다. 또한, 컨테이너와 주변환경, 네트웤, 볼륨까지 한번에 생성할 수 있다. 즉 

2. Dockerfile은 이미지를 만들기 위한 것이다. 도커 이미지 내에 여러 서비스를 넣어둘 수 있긴하지만, 동작상태의 컨테이너가 아닌 붕어빵 틀에 해당하는 이미지를 만들기 위한 것이다.

3. 쿠버네티스도 여러개의 컨테이너를 오케스트레이션(=다수의 컨테이너를 운용)한다는 점에서 동일하다. 단, 관리기능이 더 자세하다. 

즉, 도커 컨테이너-> docker compose, 도커 이미지->Dockerfile에 해당하다.  도커 컴포즈와 쿠버네티스의 차이는 컨테이너는 더 자세히 관리할 수 있는 툴인 것에 비해서, 도커 컴포즈는 단순히 여러 컨테이너를 정지/삭제 정도밖에할 수 없다.

 

 

 

도커 컴포즈 작성하는 법: 도커 컴포즈에서 쓰는 YAML파일 작성방법


도커 컴포즈는 한 파일 내에 docker-compose.yml 파일 있으면된다. 여러 도커 컴포즈를 생성할 경우, 각 폴더별로 docker-compose.yml파일이 있어야 한다. 꼭 "docker-compose.yaml"으로 YAML파일이 있을 필요는 없으나, 하나씩은 있어야한다. 도커 컴포즈의 파일은 아래와 같이 작성한다. "version"을 제외하고 "services", "networks", "volumes"은 모두 s가 붙는다

1) version 을 적는다

2) services

3) networks (옵션)

4) volumes (옵션)

# example) docker-compose.yaml
version: "3.9"
services:
  web:
    build: .
    ports:
      - "8000:5000"
  redis:
    image: "redis:alpine"

 

 

Docker compose 명령어: up, down, stop


// 도커 컴포즈내에 정의된 컨테이너 실행
$ docker-compose -f [docker-compose_file_path] up 옵션

// 도커 컴포즈내에 정의된 컨테이너만 정지
$ docker-compose -f [docker-compose_file_path] stop 옵션

// 도커 컴포즈내에 정의된 컨테이너만 종료/삭제, 네트워크 종료
$ docker-compose -f [docker-compose_file_path] down 옵션

 

아래와 같이 도커 컴포즈에 정의된 컨테이너 2개와 네트워크1개를 한번에 폐기할 수 있다. 네트워크도 삭제되는 것에 주의하고, stop이 아닌 remove된다는 것에 주의를 기울이자.

// docker-compose에 정의된 컨테이너를 한번에 종료 후 삭제

$ docker-compose -f docker-compose.yml down
[+] Running 3/3
 - Container 03-wordpress000ex12-1  Removed                                                                                                                                                                                             1.5s
 - Container 03-mysql000ex11-1      Removed                                                                                                                                                                                             2.2s
 - Network 03_wordpress000net1      Removed                                                                                                                                                                                             0.5s

 

 

Reference

[1] https://docs.docker.com/compose/

[2] https://docs.docker.com/compose/gettingstarted/

 

 

반응형

 

요약

볼륨 마운트은 도커가 관리하는 시스템내 영역을 정의/생성해서, 해당 영역을 다른 컨테이너들이 공유할수 있도록 마운트하는 것이며, 이와 다르게 바인드 마운트은 도커가 관리하지 않는 호스트의 파일시스템에 다른 컨테이너들이 공유할 수 있도록 마운트하는 것이다. 바인드 마운트는 일반적인 리눅스의 디스크 마운트를 다른 서버에서도 쓸 수 있도록 1:N으로 마운트하는 것과 동일하다.

 

파일 복사


컨테이너와의 호스트 간의 파일의 복사는 방향이 중요하다. 도커에서는 컨테이너 -> 호스트, 호스트->컨테이너간의 양방향으로 파일을 복사가 가능하다 (이 때의 호스트는 "도커 엔진을 실행중인 PC을 의미한다).

// 호스트 -> 컨테이너
$ docker cp 호스트경로 컨테이너명:컨테이너_내부경로

// 컨테이너 -> 호스트
$ docker cp 컨테이너명:컨테이너_내부경로 호스트경로

 

볼륨마운트


 

1. 볼륨 마운트: 도커엔진이 관리하는 영역내에 만들어진 볼륨을 컨테이너에 디스크 형태로 마운트함. 즉, 도커가 이미 관리하고 있는 영역인데, 일부 컨테이너한테 할당하는 개념이다. 이 영역은 도커 엔진 위에서 관리되어야한다. 임시목적으로 주로 쓴다.

- 장점:  1) 도커엔진의 관리하에 있기 때문에("var/lib/docker/volumes"), 실수로 "/home/user/documents/"등에 있는 파일들을 지워도 따로 보관된다. 또한, 2) 바인드 마운트에 비해서, 경로의 기재방식이 동일하기 때문에, 환경에 따라 경로지정을 할 필요없다. 예를 들어, Windows에서 만든 docker container을 바인드마운트 했다고 생각하면, "C:\...\"이지만, 리눅스에서는 "/var/" , "/home/..."이하일 수도 있다. 

- 단점: 도커 컨테이너를 통하지 않고서는 직접 접근이 어렵다. 백업을 하려고해도 쉽게 copy해서 가져가기 어렵다.  

 

2. 바인드 마운트: 도커엔진이 관리하하지 않아 되는 기존의 영역(예, 바탕화면, 내 문서 폴더 등에 해당)에 컨테이너에 마운트하는 방식이다. 디렉토리가 아니라 파일단위로도 마운트가 된다. 이 경우는 도커엔진의 관리하에 있지 않기 때문에, 실수로 다른유저들이 데이터를 지우면 같이지워진다.

- 장점: 기존 시스템에서 쓰던 디렉토리를 쉽게 마운트 할 수 있다.

 

정리하자면, 주어진 문제에 따라 다음과 같이 나눌 수 있다.

파일이 지워지면 안된다-> 볼륨마운트

직접 파일을 접근할 일이 많다-> 바인드 마운트

 

마운트 방법은 아래와 같다.

// 볼륨 마운트
$ docker volumn create 볼륨명

// 볼륨 마운트 삭제
$ docker volumn rm 볼륨명

 

 

 

반응형

쿠버네티스에서 kubectl get pods 등 여러 명령어를 치더라도 아래와 같이 에러를 반환하는 경우가 있다. 

The connection to the server localhost:8080 was refused - did you specify the right host or port 

 

원인: 마스터노드에서의 kubectl 관련 config가 설정이 되지 않았기 때문


쿠버네티스 초기화 내 config가 설정이 안되어있는 경우로 생각된다. 실제로 master 노드에서의 config을 확인해보면 아래와 같다.

 

 

해결방법1: (마스터노드만) kubeadm을 이용한 마스터노드의 초기화


쿠버네티스 kubeadm을 설치가 안되어있다면 설치가 필요하고, 설치했음에도 에러가 떴다면 초기화 해주는 과정이 필요하다.

설치를 한적이 없으면, 여기 URL 에서 kubeadm을 설치하는 과정을 따라하여 설치한다. 아래의 리눅스 운영체제 또는 패키지관리도구를 이용해서 설치할 것인지 말것인지 결정해서 1~4번까지 복붙하여 따라한다. 설치되어있으면 kubeadm을 초기화한다.

 

아래의 명령어로 쿠버네티스 마스터노드의 kubeadm을 초기화해준다.

sudo kubeadm init // 처음 설치한 경우
sudo kubeadm reset // 이미 설치한 경우

 

위의 명령어로도 쿠버네티스 마스터노드가 초기화 안되고 에러가 뜨는 경우가 발생했는데, 필자의 경우는 도커의 설치가 되지않아 초기화되지 않았다. 마찬가지로 도커설치도 진행한다. docker.io라고 할지 어떤 종류를 할지는 sudo apt-get install docker을 한번 실행해보면, 가이드를 해주는 설명이 출력된다.

sudo apt-get install docker.io

 

그리고나서 다시 kubeadm으로 마스터노드를 초기화 한다. 그러면, 아래와 같이 정살정으로 kubectl 관련 서비스들이 생성된다.

그림. 마스터노드에서의 쿠버네티스 초기화 작업. 자세히보면 마스터노드에서 필요한 서비스들이 생성된다. 예를 들어 etcd와 같은 클라이언트 노드들의 상태를 보관하는 저장소들도 하나씩 생성해나간다.

 

관련 리소스들이 제대로 설치가 되었는지 아래와 같이 namespace을 검색해본다.

# kubectl get pods --all-namespaces

 

해결방법2: WorkerNode인경우


마스터노드와의 Join이 안되는 경우에 이런 문제가 발생 수 있다. 마스터노드에서 다음의 명령어로 해당 노드가 제대로 참여중인지 확인한다. 아래의 명령어로 control-plane과 해당 worker노드가 확인되어야한다. 확인되지 않으면, 워커노드가 클러스터로 join이 안된것이다.

# kubectl get nodes

 

워커노드가 클러스터에 조인이 안되었음을 확인했다면, 일단 워커노드를 초기화한다.

# kubeadm reset

그리고 마스터노드에 join에 필요한 hash, cluster API및 포트, token정보를 받아온다.

// 마스터노드에서
root@k8s-master:/home/ubuntu# kubeadm token create --print-join-command
kubeadm join 172.16.2.231:6443 --token 8yxfot.ktr4irill5hqw6h7 --discovery-token-ca-cert-hash sha256:bd91d60981b5774add11106cd42e1f8d6db18b241b5fd529b0d638e71

다시 워커노드에서 위의 명령어를 복붙하여 조인한다.

root@k8s-test:/home/ubuntu# kubeadm join 172.16.2.231:6443 --token 8yxfot.ktr4irill5hqw6h7 --discovery-token-ca-cert-hash sha256:bd91d60981b5774add11106cd42e1f8d6db18b241b5fd529b0d638e713522494
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

 

반응형

쿠버네티스의 컨트롤러는 특정 Pod의 수를 보장해주는 역할을 하는 자원을 의미한다. 아래의 쿠버네티스의 마스터노드(컨트롤플레인)가 어플리케이션을 각 노드에서 실행하고, 이를 각 etcd에서 제대로 수행되고 있는지 모니터링하다가 부족한 Pod은 더 실행해주고, 많은 Pod은 종료시켜주는 역할을 한다.

그림. 쿠버네티스 동작원리

 

쿠버네티스의 컨트롤러의 종류


쿠버네티스 컨트롤러는 Replication controller, replicaset, deployment, daemonset등 여러가지가 있어서 헷갈린다. 이 자원들은 모두 다 컨트롤로에 속한다. 다만 각각의 자원들이 쿠버네티스가 발전해나감으로서 생긴 디테일의 차이(대동소이)한 것들이 있어서 몇가지 대표적으로 필요한 것들만 알아보면 좋다. 사용목적에 따른 대표적인 것들은 아래와 같다.

  • 오랜시간 켜두어야할 어플리케이션이 파드로 존재하는 경우: Replication contoller, Replicaset, Deploment
  • 클러스터에 속한 전체 노드에 같은 파드를 실행해야하는 경우: Daemonset
  • 일회성 작업을 해야할 때: Job
  • 주기적인 배치작업을 해야하는 경우: Cronjob

자세히는 아래와 같다. 리플리케이션 컨트롤러 (Replication controller)은 쿠버네티스 초기부터 있던 컨트롤러로, 지정된 숫자만큼 파드의 개수를 항상 보장해줄 수 있도록 제어해주는 컨트롤러이다. 요즘은 이 리플리케이션 컨트롤러보다 리플리카셋(replicaset)을 주로 이용하거나, 앱 배포면 디플로이먼트(deployment)을 이용한다고 한다.

사용방법은 아래와 같다. 1) Kind에 replicationContoller라고 적는다. 2) spec.replicas내에 몇개의 파드를 유지할 것인지를 명시한다. 3) selector은 레이블이 동일한 어떤 파드를 관찰할 것인지를 명시하는 것이다. 여기서는 app: my-ngnix라는 라벨을 가진 파드를 바라보고 관찰한다. 4) template은 명시한 파드가 개수가 부족한 경우, 어떤 스펙으로 다시 만들지를 정의한다. *주의할 것은 selector이하의 속성값과 template.labels의 속성값은 동일해야 에러가 안난다.

아래와 같은 rc의 실행결과를 확인할 수 있다.

PS C:\Users\PC\Documents\repository\kube> kubectl get rc
NAME    DESIRED   CURRENT   READY   AGE
my-rc   3         0         0       24s

 

리플리카셋(Replicaset, RC): ReplicationContorller의 확장판(+POD 검색기능)


ReplicationContoller은 POD의 개수를 보장한다고 했다. 리플리카셋도 마찬가지로 POD의 개수를 보장한다. 하지만, 리플리카셋이 추가적으로 해주는 기능은,

 "="의 selector외에 집합연산자 (in, notin)등을 지원해서 저 쉽게 사용할 수 있다. 리플리카셋의 spec에는 matchLabels과 matchExpressions라는 것을 사용할 수 있는데, matchLabels은 리플리케이션컨트롤러가 해주는 기능과 비슷하다. 다만, matchExpressions으로 좀더 상세하게 POD의 선정을 할 수 있다. 가령 아래와 같이 matchExpression을 써주면 key의 In조건에 맞는 POD들만 선택해서 관리할 수 있다.

# replicaset.yaml

...
spec:
    replicas:3
    selector:
         matchLabels:
             app: my-app
         matchExpression:
             {key: verison, operator: In, value:["3.5", "2.1"]}

 

하지만 matchExpressions을 꼭 써야하는 것은 아니다. 다음과 같이 작성해도 충분히 동작한다.

위와 같이 파드의 개수를 3개로 유지하게끔 선언했는데, 아래와 같이 파드가 1개 생성된 경경우는 2개가 아직 모종의 이유로 생성되지 안음을 확인할 수 있다. cpu 요구량을 못맞춰서 중단된것을 알 수 있다.

> kubectl get pods
NAME                  READY   STATUS              RESTARTS   AGE
my-replicaset-q42qp   0/1     ContainerCreating   0          3s

> kubectl describe replicaset my-replicaset
....
Events:
  Type     Reason            Age                 From                   Message
  ----     ------            ----                ----                   -------
  Normal   SuccessfulCreate  2m7s                replicaset-controller  Created pod: my-replicaset-q42qp
  Warning  FailedCreate      2m7s                replicaset-controller  Error creating: pods "my-replicaset-86kwg" is forbidden: exceeded quota: mem-cpu-demo, requested: requests.cpu=1, used: requests.cpu=1, limited: requests.cpu=1
  Warning  FailedCreate      2m7s                replicaset-controller  Error creating: pods "my-replicaset-n4rkz" is forbidden: exceeded quota: mem-cpu-demo, requested: requests.cpu=1, used: requests.cpu=1, limited: requests.cpu=1
  Warning  FailedCreate      2m7s                replicaset-controller  Error creating: pods "my-replicaset-jg6xc" is forbidden: exceeded quota: mem-cpu-demo, requested: requests.cpu=1, used: requests.cpu=1, limited: requests.cpu=1
  Warning  FailedCreate      2m7s                replicaset-controller  Error creating: pods "my-replicaset-66pht" is forbidden: exceeded quota: mem-cpu-demo, requested: requests.cpu=1, used: requests.cpu=1, limited: requests.cpu=1
  Warning  FailedCreate      2m7s                replicaset-controller  Error creating: pods "my-replicaset-5zg4z" is forbidden: exceeded quota: mem-cpu-demo, requested: requests.cpu=1, used: requests.cpu=1, limited: requests.cpu=1
  Warning  FailedCreate      2m7s                replicaset-controller  Error creating: pods "my-replicaset-8ns6f" is forbidden: exceeded quota: mem-cpu-demo, requested: requests.cpu=1, used: requests.cpu=1, limited: requests.cpu=1
  Warning  FailedCreate      2m7s                replicaset-controller  Error creating: pods "my-replicaset-w5gsb" is forbidden: exceeded quota: mem-cpu-demo, requested: requests.cpu=1, used: requests.cpu=1, limited: requests.cpu=1
  Warning  FailedCreate      2m6s                replicaset-controller  Error creating: pods "my-replicaset-8j4dh" is forbidden: exceeded quota: mem-cpu-demo, requested: requests.cpu=1, used: requests.cpu=1, limited: requests.cpu=1
  Warning  FailedCreate      2m6s                replicaset-controller  Error creating: pods "my-replicaset-vtqgv" is forbidden: exceeded quota: mem-cpu-demo, requested: requests.cpu=1, used: requests.cpu=1, limited: requests.cpu=1
  Warning  FailedCreate      24s (x8 over 2m6s)  replicaset-controller  (combined from similar events): Error creating: pods "my-replicaset-fx7rt" is forbidden: exceeded quota: mem-cpu-demo, requested: requests.cpu=1, used: requests.cpu=1, limited: requests.cpu=1

 

디플로이먼트(Deployment)


컨트롤러기보다는 컨트롤러인 레플리카셋(RS)을 제어해주는 역할이다. 디플로이먼트의 가장 큰 목적은 롤링업데이트(Rolling update) 또는 롤링백(Rolling back)을 하기위함이다. 롤링업데이트의 자세한 설명은 링크와 같다. 소프트웨어를 업데이트를 위한 것인데 요약하면 "롤링 업데이트는 파드가 여러 개 있다고 했을 때, 한 번에 모든 파드를 동시에 버전업하는 것이 아닌, 파드를 하나씩 업데이트해서 무중단 업데이트를 해주는 과정"이라고 생각하면 된다. 핵심은 "무중단 + 업데이트"이다.  

Deployment은 정확히는 컨트롤러는 아니고, 컨트롤러인 Replicaset을 제어하는 자원이다. Replicaset은 POD을 제어한다.

아래와 같이 대화형 튜토리얼을 이용하면 예시를 직접 해볼 수 있다(링크). 아래의 이미지를 보면, 이름이 "kubernetes-bootcamp"인 deployment가 하나가 실행됨을 확인할 수 있다. 위에서도 디플로이먼트가 레플리카셋을 제어한다고하니, 레플리카셋이 하나 있을 것이고, 레플리카셋은 또 파드를 제어하니, 파드의 생성도 함께 확인할 수 있을 것이다.

그러면, 디플로이먼트를 사용하려면 어떻게 yaml파일을 작성해야하나? 일단, deployment의 버전을 확인하기위해서 아래와 같이 확인한다. deployment은 apps/v1의 APIVERSION에 있다.

PS C:\Users\PC> kubectl api-resources
NAME                              SHORTNAMES   APIVERSION                             NAMESPACED   KIND
...
deployments                       deploy       apps/v1                                true         Deployment

그리고 아래와 같이 스펙에 맞춰 yaml파일을 작성한다. 형태는 replciaset과 동일하다.

apiVersion: apps/v1
kind: Deployment
metadata:
    name: my-deployment
spec:
    replicas: 2
    selector:
        matchLabels:
            app: my-nginx
    template:
        metadata:
            name: nginx-pod
            labels: 
                app: my-nginx
        spec:
            containers:
            -   name: nginx-container
                image: nginx:latest
                resources:
                    limits:
                        memory: 500Mi
                        cpu: 1
                    requests:
                        memory: 500Mi
                        cpu: 1

 

그러면 아래와같이 동작하는 것을 확인할 수 있다. (POD 하나는 리소스 이유 때문에 동작은 하지 않았다.)

PS C:\Users\PC\Documents\repository\kube> kubectl get all -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP          NODE             NOMINATED NODE   READINESS GATES
pod/my-deployment-cff6c8d86-jgb5g   1/1     Running   0          12s   10.1.0.25   docker-desktop   <none>           <none>

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   44d   <none>

NAME                            READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS        IMAGES         SELECTOR
deployment.apps/my-deployment   1/2     1            1           12s   nginx-container   nginx:latest   app=my-nginx

NAME                                      DESIRED   CURRENT   READY   AGE   CONTAINERS        IMAGES         SELECTOR
replicaset.apps/my-deployment-cff6c8d86   2         1         1       12s   nginx-container   nginx:latest   app=my-nginx,pod-template-hash=cff6c8d86

 

 

Deployment을 이용하여 pod을 스케일업하기: kubectl scale deployment [deployment명] --replicas=3

아래의 그림과 같이 deployment은 Replica Set(RS)을 선언적으로 지정해서 관리한다. 또한, Replica Set은 pod을 선언적으로 관리한다.(선언적= 지정한대로 개수, 자원등을 보장해줌). 따라서, deployment을 생성해놓고, replicaset 또는 pod을 직접 관리하면, 삭제되고 재생산된다. 따라서, pod수나 replicas을 변경하고싶으면 deployment을 이용해서 조작해야한다.

Deployment, Replica Set, Pod의 관계예시: 자료(https://theithollow.com/2019/01/30/kubernetes-deployments/)

아래와같이 쿠버네티스 공식홈페이지에 있는 것과 동일하게 웹서버인 nginx을 서비스하는 deployment을 정의했다.

 

이를 이용해서 Deployment 및 스케일업을 아래와같이 진행해볼 수 있다. 아래의 코드블럭처럼 replicas을 조절하면 replicas에 딸려있는 pod수가 조절되므로 replicas을 조정해도 된다. replicas을조정하기위해서는 deployment을 조정한다. 

// deployment 자원의 생성
$ kubectl create -f nginx-deployment.yaml
deployment.apps/nginx-deployment created

// 자원이 생성되었는지 확인
$ kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           18s

// replicas을 5개로 스케일업
$ kubectl scale deployment nginx-deployment --replicas=5
deployment.apps/nginx-deployment scaled


// 스케일업 되었는지 pod수를 확인
$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-7fb96c846b-88ctt   1/1     Running   0          52s
nginx-deployment-7fb96c846b-dqbhk   1/1     Running   0          7s
nginx-deployment-7fb96c846b-jhgq2   1/1     Running   0          52s
nginx-deployment-7fb96c846b-m2bbg   1/1     Running   0          7s
nginx-deployment-7fb96c846b-xj74r   1/1     Running   0          52s

그리고, kubectl descirbde 을 이용하면 아래와같이 스케일업된것을 확인할 수 있다.

 

 

롤링업데이트의 사용은 어떻게 해야하나? 예시로 

# set 명령어 인자
kubectl set image deployment <디플로이먼트 이름> <컨테이너이름>=<새 버전>

# 디플로이먼트 내 컨테이너 ngnix 을 1.9.1로 업데이트
kubectl set image deployment/nginx nginx=nginx:1.9.1

# 모든 디플로이먼트와 RC의 컨테이너 내에 있는 ngnix이미지를 1.9.1로 업데이트
kubectl set image deployments,rc nginx=nginx:1.9.1 --all

*references:https://www.macstadium.com/blog/how-to-k8s-pods-replicasets-and-deployments

 

Deployment의 정지: kubectl delete deployment [deployment명]

// deployment 상태확인
$ kubectl get deployment
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
simple-app-deployment   3/3     3            3           11m


$ kubectl delete deployment simple-app-deployment
deployment.apps "simple-app-deployment" deleted

 

 

스테이트풀세트(Stateful set)


작성중

 

데몬세트(Daemon set)


작성중

 

잡 컨트롤러(Job contoller)


작성중

 

크론잡(Cronjob)


작성중

 

기타(트러블 슈팅)


이슈1: error: resource mapping not found for name: "my-rc" namespace: "" from ".\\my_rc.yaml": no matches for kind "ReplicationContoller" in version "v1" ensure CRDs are installed first

해결방법: 아래와 같이 쿠버네티스에서 지원하는 자원들과 APIVERSION을 확인한다. 참고로 해당 이슈는 "ReplicationContoller"을 kind에 썼는데, 아래와 같이 "ReplicationController"에 오타가 난 것을 알 수 있다. 즉, 아래의 리스트의 KIND와 동일한 KINDS을 써주어야한다.

$ kubectl api-resources
NAME                              SHORTNAMES   APIVERSION                             NAMESPACED   KIND
bindings                                       v1                                     true         Binding
componentstatuses                 cs           v1                                     false        ComponentStatus
configmaps                        cm           v1                                     true         ConfigMap
endpoints                         ep           v1                                     true         Endpoints
events                            ev           v1                                     true         Event
limitranges                       limits       v1                                     true         LimitRange
namespaces                        ns           v1                                     false        Namespace
nodes                             no           v1                                     false        Node
...

 

이슈 2: 리플리카셋에서 아래와 같이 메시지가 나온 경우(failed quota) Error creating: pods "my-replicaset-vvh6n" is forbidden: failed quota: mem-cpu-demo: must specify limits.cpu for: nginx-container; requests.cpu for: nginx-container

해결방법: 리플리카셋 내 template.spec.container.resources 내에 limit 또는 reqeusts을 명시한다.

반응형

의외로 다른 IT 프로젝트와 달리, 특히 AI 프로젝트의 성공율이 15%정도라고 한다. 왜 15%밖에 안되는 것인가? 해당 보고서에는 아래와 같이 설명하고 있다.

  • ML은 아직 리서치 단계(연구단계)의 작업들이다. 따라서, 애초에 프로젝트 시에 무조건 된다는 버려야 한다.
  • 기술적을 불가능한 문제를 푸려고 한다.
  • 프로덕션 단계를 고려하지 않는다.
  • ML 프로젝트의 성공여부가 불분명하다.
  • 팀 관리가 안된다.

 

Lifecycle (생애주기)


ML project의 생애주기는 ML 프로젝트에 각각 무엇이 수행될 수 있는지에 관한 내용이다. 크게는 프로젝트 계획하기-> 데이터 수집 및 라벨링 -> 모델 학습 및 디버깅 -> 모델 적용 및 테스트로 구분된다. 이 단계가 무조건 1, 2,3,4의 순차적인 단계로 실행되는 것은 아니고, 진행하던 단계가 문제에 봉착했는데 풀 수 없을 경우는 이전, 또는 더 이전단계로 돌아가서 계획부터 다시 할 수 있다는 것을 알아야 한다.

ML 프로젝트의 생애주기

- 프로젝트 계획하기(Planning and Project setup): 실제 문제를 풀어 나갈 것인지, 목표는 무엇인지, 리소스는 어떤 것들이 있는지 파악하는 단계이다.

- 데이터 수집 및 라벨링(data collection and labeling): 훈련용 데이터를 수집하고, ground truth(실제 참이라고 할 수 있는 라벨)을 이용하여 데이터를 라벨한다. 만일 이 단계에서 뭔가 문제가 있거나 데이터를 구하기 어려우면 프로젝트 계획부터 다시 실행하는 것을 권장한다.

- 모델 학습 및 디버깅(Model traning and debugging): 이 단계에서는 베이스 라인 모델을 빨리 적용해놓고, 가장 좋은 모델들을 찾아서 성능을 높혀나가는 것을 의미한다. 그리고 이 단계에서는 뭔가 라벨링이 이상하거나 데이터가 더 필요한 경우는 이전 단계인 "데이터 수집 및 라벨링" 단계로 돌아간다. 혹은 문제가 너무 어려워서 풀지 못할 것 같거나, 프로젝트 요구사항에서 밀릴 경우는 프로젝트 게획하기 단계부터 다시 실행한다.

- 모델 적용 및 테스트(ML Deploying and Model testing): 이 단계에서는 파일럿 모델을 연구실 환경에서 한번 돌려보고, 잘되는지 확인하고, 실제 프로덕션 단계로 적용한다. 만일, 성능이 애초에 안나오는 경우, 모델 학습 및 디버깅 단계로 돌아간다. 또는 데이터가 더 필요하거나, 훈련데이터랑 실제 데이터랑 너무 안맞는 경우 데이터 수집 및 라벨링 단계로 간다. 마지막으로 실제 환경에서 잘 동작하지 않거나, 사용자의 사용 환경과 너무 안맞는 결과들이 나올 경우에는 계획부터 다시해야할 수도 있다.

 

프로젝트의 우선순위 결정하기(Priortizing projects)


ML프로젝트를 실행하기전에, 이 프로젝트가 얼마나 비지니스 모델에 영향을 줄 것인지? 아래의 그림처럼, 가능한 실현가능성도 높고, 실제 비지니스에 영향을 줄만한 프로젝트를 하는 것이 중요하다. 

영향도 평가: 니즈(Needs). 니즈를 파악하는 것은 얼마나 의사결정 과정에서 마찰을 경험하고 있는지를 파악해보는 것이다. ML의 장점(Strength)은 Software 2.0(데이터가 많아질 수록 성능이 강력해지는 소프트웨어)과 데이터가 실제 복잡한 규칙기반의 소프트웨어이며, 이 규칙이 데이터로 학습할 수 있는 지를 의미한다. 

실현가능성 평가(Feasibiltiy): 실현 가능성을 평가하는 것들중에 비용이 많이 드는 순서로 문제의 난이도 -> 요구되는 모델의 정확성 -> 사용가능한 데이터순으로 높다. 첫 째로 가장 문제가되는 데이터는 "데이터가 많은지", "얻기 쉬운지?", "얼마나 많이 필요할지" 등이다. 흔히 생각할 수 있는 내용이다. 둘 째로, 모델의 정확도 요구사항은 혹시 모델이 틀렸을 때 얼마나 비용이 많이 드는지, 어느정도 정확해야 쓸만한지, 윤리적인 이슈는 없는지에 관한 내용이다. 마지막으로 문제의 난이도는 "문제가 잘 정의도리 수 있는지", "이전에 해결한 문제들은 없는지" 컴퓨팅 요구사항"은 되는지, 사람이 할 수 있는일인지에 관한 내용이다.

 

아키텍처(Archetypes)


ML 프로젝트의 메인 카테고리로, 프로젝트 관리 및 구현을 어떻게 할 것인지에 관한 내용이다. 이 챕터는 그 원형(Archetypes)에 대한 얘기로, 크게 3가지로 분류되며, Sofware 2.0, HITL(Human in the loop), Autonomous system이다. 본인이 풀고자하는 문제들이 어느부분에 해당하는지, 어떻게 구현되는지 개념적으로 명확히 이해하는데 도움을 줄 수 있다.

  • Software 2.0: 소프트웨어의 성능이 데이터가 많아질 수록 강력해지는 것을 의미한다. 기존의 규칙기반 시스템을 능가하는 것을 의미한다.
  • HITL: 사람의 컨펌하에 쓰는 소프트웨어이다. 가령, 구글 이메일 작성시, 오토 컴플릿되는 것을 의미한다.
  • 자동화 시스템: 사람 손을 안타는 시스템이다.

 

평가지표(metrics)


위의 내용처럼 어떻게 구현하겠다라는 가이드가 잡히면, 실제로 어떤 지표를 삼아야 성공여부를 달성했는지, 효율적으로 평가할지를 알 수 있다. 당연하겠지만 평가도구는 모델의 성능을 평가할 수 있는 지표를 삼아야한다. 처음에는 모델을 성능을 단순히 평가할만한 하나의 지표로 삼다는다. 그 후에, 안정화되면, 여러 평가지표를 복합적으로 쓸 수 있다. 가령, 평균적인 모델의 성능은 어느정도가 되어야하는지지표(average)와 지표를 넘는지 안넘는지 임계치(Threshold)로 계산해볼 수 있다. 가령 임계치는 모델 몇 MB이하여야한다 정도로 써볼 수 있다. 

 

베이스라인 모델 구하기


실제 ML프로젝트를 하다보면 무조건 SOTA(State of the Art)부터 가져와서 적용할라다보니까, 어렵다. 그리고, SOTA을 적용하다가 너무어려워서 다 따라가지도 못하고 접는 경우도 생긴다. 그리고 SOTA부터 적용하니까 어느정도가 적정한 모델 성능인지 파악하기 어렵다. 베이스라인 모델을 구해서 적용해보는 것은 위의 내용을 파악하는데 도움을 준다. 베이스라인 모델은 대강 우리의 모델이 어느정도 성능이 나올 것이다하는 바로미터로 써볼 수 있다. 예를 들어, 질병 추천시스템의 Top 5 Recall이 대충 선형회귀로 해도 80%가나오면 이문제는 어느정도 풀만한 모델이고, 잘만하면 90%도 나올 수 있다는 것을 알 수 있다. 

반응형

Pod(파드): 여러 컨테이너를 묶어 놓은 논리적인작업 단위이다. 파드 내에는 1개의 컨테이너가 존재할 수 있고, 여러 개의 컨테이너가 존재할 수도 있다. 1개만 존재하면 싱글 컨테이너 파드, 2개 이상 존재하면 멀티 컨테이너파드라고 부른다. 그럼 컨테이너는 무엇인가? 하나의 "어플리케이션"이라고 생각하면 된다. 파드에는 여러 개의 컨테이너가 존재할 수도 있기 때문에, 웹 서버 컨테이너, 로그 수집기, 볼륨(=디스크)을 묶어 하나의 파드로 구성할 수도 있다. 

 

파드 사용하는 방법

 


파드를 사용하는 방법은 CLI(커멘드 명령의 인터페이스)로 실행시키는 방법이 있고, 아래의 그림과 같이 YAML포맷의 파일을 이용해서 생성하는 방법이 있다.

  • metdata.name: 값에 해당하는 필드 및 필드명은 이 파드의 이름을 설정하기 위함이다. 
  • spec.containers: 이 필드아래에 container을 적으면 하나씩 컨테이너가 생긴다. 아래의 예시는 컨테이너 1개를 생성하는 예시이다. "-"(하이픈)은 하위필드를 배열로 묶겠다는 것이다. 즉, 파이썬의 딕셔너리로 생각하면 {"spec": {"container": [{"image":"nginx":"latest"}, {"name":"my-nginx"}, {"resources": {}}]와 같이 속성들을 containers의 하위 필드 배열로 취급하겠다는 것이다.
  • spec.containers.image: 컨테이너에 사용될 이미지명을 적는다, ":"앞은 어플리케이션 명,  뒤는 어플리케이션의 버전정보이다. 사용자가 다운로드 받지 않아도, 이 컨테이너를 실행하는 순간에 컨테이너 허브에서 이 이미지를 다운로드(PULL)하여 가져온다.

 

Pod 생명주기


파드 생명주기는 파드 생성부터 파드의 삭제, 실패까지의 과정 중에 각각 어느단계에 있는지에 대한 개념이다. 만일 파드가 러닝중인지? 생성중인지? 실패했는지에 관한 내용을 알 수 있다. 일단 파드가 한번 생성되면 유니크안 식별자(UID, Unique ID)을 갖는다. 그리고, 삭제되기 전까지는 유지된다. 파드 생명주기 중에 어느 상태인지는 status의 필드로 확인할 수 있다.

이름이 mywebserver인 STATUS가 실행중인 파드. 어플리케이션은 1개중에 1개가 구동중

각 단계별로 의미하는 것은 아래와 같다.

상태(STATUS) 의미
Pending 쿠버네티스 클러스에서 일단 실행이 가능한 상태라고 판명된 상태. 하지만, 컨테이너중에 몇개는 아직 구동을 준비중인 상태를 의미한다. (=즉, "만들어지는 중이에요" 라는 상태)
Running 파드 내에 모든 컨테이너가 구동중인 상태
Succeeded 파드 내 모든 컨테이너가 구동에 성공된 상태. 
Failed 파드 내 모든 컨테이너가 종료된 상태. 정상 실행이 아닌 (non-zero status) 컨테이너가 존재하는 상태. 
Unknown 모종의 이유로 컨테이너 상태를 얻을 수 없는 경우

 

LivenessProbe 사용하기: 자동으로 컨테이너가 죽는 경우, 재시작 하기


kubernetes의 livnessProbe의 동작 방식 그림 (참조: https://komodor.com/learn/kubernetes-liveness-probes-a-practical-guide/)

 

  • livenessProbe을 이용해서 컨테이너 sefl-healing 이용하기

livenessProbe가 동작하는 방식은 httpget probe, tcpSocket probe, exec probe라는 것을 이용해서 각각의 목적에 맞는 일부 기능들을 주기적으로 체크를 해서 컨테이너가 정상적으로 동작 중인지를 확인한다. 예를 들어, http 웹서버라면, httpget probe은 주기적으로, 지정한 IP, port, path에 대해서 HTTP get요청을 보내서 응답이 잘 못나오는 경우 컨테이너를 다시 시작한다. tcpSocket probe은 ssh로 접속해보고 접속이 몇 번 실패하면, 해당 컨테이너를 다시 시작하는 것이다. exec probe은 명렁을 전달하고 명령의 종료코드가 0 (정상종료)가 아니면, 컨테이너를 다시 시작하는 것이다. 중요한 것은 Pod을 재시작하는 것이 아니라 Container을 재시작하는 것이다. 따라서, Pod은 그대로 이기 때문에, IP을 동일하게 사용할 수 있다.

livenessProbe을 사용하기 위해서는 몇 가지 전달해야하는 인자가 있는데, 아래와 같다. 자세한 인자들(Configuration)은 여기에서도 확인이 가능하다. initialDelaySeoncds은 컨테이너 실행 후 몇초 뒤에 probe을 실행할 것인지에 대한 속성이다. periodSeoconds은 몇초 주기로 프로브를 실행할 것지에 대한 속성, timeoutSeconds은 프로브를 실행하고나서 몇초 내에 명령들이 종료되어야하는지에 대한 속성, seccessThreshold은 이 프로브가 몇 번 연속 성공하면 성공이라고 볼것인가에 대한 것이다. failureThreshold은 프로브가 몇 번 실패해야 실패로 볼 것인지에 대한 기각역이다.

아래의 예시는 buxybox라는 이미지를 이용해서 컨테이너 1개짜리를 담은 "liveness-exam"이라는 Pod을 생성한다. 추가로, 컨테이너를 실행할 때, 컨테이너 상의 '/tmp/healthy'라는 파일을 만들고 30초 후에 삭제하는 명렁도 같이 넣어놓았다. 즉, 컨테이너가 실행되고나서 30초 동안만 파일이 존재할 것이다.

exec livenessProbe을 사용하기위한 yaml 예시. 컨테이너 실행할 때 초기에 30초동안만 파일을 생성하고, 그 뒤에 지우는 커멘트가 들어가있다. 마찬가지로 이 파일을 cat으로 확인하는 커멘드도 포함되어 있다.

 

아래와 같이 exec livenessProbe가 실행을 몇 번해보다가, failthrehold만큼 실패하면 해당 컨테이너를 재시작한다.

위의 yaml파일에서 failureThrehold가 3번이 지정되었기 때문에, 3번 검사하고 (x3 over 11s) 실패했기 때문에, 해당 컨테이너를 삭제하고 재시작하는 것이다.

 

초기화 컨테이너(Init container): 초기화 컨테이너는 파드에 앱 컨테이너가 실행되기 전에, 실행되는 특수한 컨테이너이다. 이 초기화 컨테이너로, 앱 이미지(도커이미지)에 없는 설정, 유틸리티 스크립트를 실행하여 일부 변형을 할 수 있다.


초기화 컨테이너(init container)은 Pod내에서 어플리케이션이 동작하기전에 실행되는 특별한 컨테이너를 의미한다[ref]. 주로, 만들어진 이미지를 컨테이너로 실행하면서 추가사항을 실행하기 위한 목적으로 쓰인다. 예를 들어, 구동하고자하는 앱은 RestAPI + 딥러닝추론엔진이라면, 컨테이너에는 FastAPI이미지만 있고, 초기화 컨테이너가 실행될 때, 딥러닝추론엔진만 다운로드 받아오는 식이다. 이렇게하면 딥러닝 추론엔진이 사이즈가 엄청 크더라도(>10Gb) 한 이미지에 담을 필요없이, 이미지 + 추가실행사항 정도로 이해하면된다.

일반적인 컨테이너랑 거의 유사(리소스 제한, 볼륨 사용, 보안세팅)한데, 다른 몇 가지가 있다, 대표적으로 lievnessProbe을 지원하지 않는 것이다. 그리고 초기화 컨테이너도 일반 컨테이너(regular container)와 마찬가지로 다수의 초기 컨테이너를 사용할 수 있다. 초기 세팅이 2~3개 이상 필요한 경우, 초기화 컨테이너를 2~3개 이상 명시하는 것이다. 이 때, yaml파일에 적인 순서대로 동작한다. 먼저 선언된 초기화 컨테이너가 동작하지 않으면, 뒤의 초기화 컨테이너가 동작하지 않는다. 초기화 컨테이너의 실행이 실패하면, 쿠버네티스는 실행 될 때까지 초기화 컨테이너를 구동해본다. (=쿠버네티스의 "선언적 특징"). 그리고, 초기화 컨테이너가 다 실행되어야, 메인 컨테이너를 동작한다(=초기화 컨테이너가 실행이 안되면 메인컨테이너가 구동이 안됨)

 

아래는 일반 컨테이너를 1개 구성하고 초기 컨테이너를 2개 구성한 것이다.

# myapp.yaml
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
  - name: init-mydb
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]

 

실제 파드를 쿠버네티스에 띄워보면 아래와 같아. myapp-pod가 초기화되려고할 때, STATUS은 Init:0/2상태로 2개의 초기화 컨테이너가 파드내에서 동작해야함을 의미하고 있다.

 

그리고, kubectl desribe pod myapp-pod을 찍어보면, 첫 번째 초기화 컨테이너(init-myservice)가 실행중임을 알 수 있다.

kubectl desribe pod myapp-pod

# std out
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  13m   default-scheduler  Successfully assigned default/myapp-pod to docker-desktop
  Normal  Pulling    13m   kubelet            Pulling image "busybox:1.28"
  Normal  Pulled     13m   kubelet            Successfully pulled image "busybox:1.28" in 5.871629222s
  Normal  Created    13m   kubelet            Created container init-myservice
  Normal  Started    13m   kubelet            Started container init-myservice

 

조금 더 자세히, 첫 번째 컨테이너의 로그를 보면(kubectl logs myapp-pod -c init-myservice) 계속 실패중이다. 

$kubectl logs myapp-pod -c init-myservice | tail

# std out
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

nslookup: can't resolve 'myservice.default.svc.cluster.local'
waiting for myservice
nslookup: can't resolve 'myservice.default.svc.cluster.local'
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

waiting for myservice

위와 마찬가지로 두 번째 컨테이너의 로그를 보면, 첫 번째 컨테이너가 실패했기 때문에, 구동을 시도조차 하지 않았을 것이다.

 

 

Infra container 사용하기


싱글 컨테이너로 파드를 구동하면 일반 컨테이너(regular)가 1개 돌아가는데, 사실은 아무일도 하지 않는 Infra container (pause) 컨테이너가 숨어있다.파드 생성될 때, 1개씩 생성된다. 파드에 대한 인프라 IP, HOSTNAME 을 관리한다. 이 파드는 식별자(UID)가 1이다. 다른 컨테이너의 부모 컨테이너로 사용(다른 컨테이너를 생성할 때, 상속받듯이 사용)이 된다. 그래서, 파드 안에 새로운 컨테이너 생성되면, Infra contatiner을 참조하여 만드니까, IP, hostname이 동일하게 생성된다. 혹시나, 이 infra conatiner가 재시작이 된다면, 파드 내에 네트웍구성이(IP, hostname)가 동일해야되기때문에, 모든 컨테이너가 다시 재시작이 된다.

 

 

스태틱 파드(Static Pod)


각 워커노드에서는 kublect 이라는 데몬이 돌아이 돌아가는데, kubelet은 파드에서 컨테이너가 확실하게 돌아가게끔 관리해주는 역할을 한다. 여태까지는 컨테이너를 띄울 때, Kubectl을 통해서, 각 노드에게 명령을 전달했다. 반면, 스태틱 파드는 직접 데몬에서 실행하는 (노드에 직접 들어가서 파드를 정의하는 디렉토리(/etc/kubernetes/manifests, kubelete configuration file)에서 직접 설정하게끔 파일을 설정하면, 자동으로 kubelet이 이 파일을 참조해서 컨테이너를 만드는 데, 이것이 스태틱파드이다. 즉, API서버 없이 특정노드에 있는 kubelet에 의해 직접 실행되는 파드를 의미한다. 쉽게 말해, 수동으로 돌리는 파드이다.

# 특정 노드로 접속
$ ssh alchemist@node1

# kubelet 설정 파일을 확인
$ docker exec -it 0a5f48991df2 /bin/bash # minikube을 docker에서 띄운 경우
$ cat /var/lib/kubelet/config.yaml  | grep staticPodPath
staticPodPath: /etc/kubernetes/manifests

# PodPath에 지금 kubelet이 실행하고 있는 자원들을 확인
$ cd /etc/kubernetes/manifests
$ ls /etc/kubernetes/manifests
etcd.yaml  kube-apiserver.yaml  kube-controller-manager.yaml  kube-scheduler.yaml

# nginx을 예시로 실행하기 
$ vi nginx-pod
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: nginx-pod
  name: nginx-pod
spec:
  containers:
  - image: nginx:latest
    name: nginx-pod
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

# control-plane으로 들어와서
$ kubectl get pods
NAME                 READY   STATUS    RESTARTS   AGE
nginx-pod-minikube   1/1     Running   0          14s

 

Pod 생성시 컨테이너에서의 자원 제한하기(requests, limits)


Pod을 생성할 때, 각 컨테이너가 어느 노드에 실행될지는 컨트롤플래인(control-plane)의 스케쥴러가 확인해준다고 했다. 사용자가 지정으로 "특정 컨테이너를 돌릴 때, 적어도 이정도 자원이 필요해요", 또는 "특정 컨테이너를 돌릴 때, 다른 컨테이너에 영향안받게 최대 여기까지만 자원을 할당해주세요" 와 같이 요구사항/제한을 둘 수 있다. 전자(특정 컨테이너를 돌릴 때, 적어도 이정도 자원이 필요해요)는 requests, 후자(특정 컨테이너를 돌릴 때, 다른 컨테이너에 영향안받게 최대 여기까지만 자원을 할당)은 limits을 의미한다. 혹여나 컨테이너가 limits의 자원을 넘어서 할당되면, 해당 파드가 죽게되고, 다시 스케쥴링이 된다. Requests은 container을 생성할 때, 어느 최소요구사항을 만족하는 node을 찾아달라는 요청이다. 신기하게도? limits을 넣으면 requests도 같은 크기로 함께 자동으로 갖게된다.

쿠버네티스에서는 메모리의 크기는 Mi단위로 표현하고, CPU은 숫자(코어수), 또는 1000mc(밀리코어, 1CPU)로 표현한다.

 

# ngnix-pod.yaml 작성
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
  - image: nginx:latest
    name: nginx-container
    ports:
    - containerPort: 80
      protocol: TCP
    resources:
      requests:
        memory: 500Mi
        cpu: 1
        
# Pod생성
kubectl create -f ngnix-pod.yaml
  
# 파드 확인
kubectl describe pod <파드명>
 Containers:
  nginx-container:
    Container ID:   docker://8cb4710e30e4ac033276b51361791de5ff9b39edfdc84ff6e315ab71f8af8d38
    Image:          nginx:latest
    Image ID:       docker-pullable://nginx@sha256:db345982a2f2a4257c6f699a499feb1d79451a1305e8022f16456ddc3ad6b94c
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Tue, 19 Jul 2022 14:20:39 +0000
    Ready:          True
    Restart Count:  0
    Requests:
      cpu:        1
      memory:     500Mi
    Environment:  <none>
    Mounts:

 

 

환경변수 설정하기


Kubernetes에서 컨테이너를 실행할 때, 컨테이너에  내에서 쓰이는 환경변수를 설정할 수 있다. 아래와 같이 컨테이너(Containers)이하에 env라는 속성명 이하에 담으면 된다.언제 쓰느냐? 도커 컨테이너에서 정의된 환경변수외에 추가로 필요하거나, 변경할 때 필요하다. 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
  - image: nginx:latest
    name: nginx-container
    ports:
    - containerPort: 80
      protocol: TCP
    env:  # 환경변수의 설정
    - name: env_name
      value: "test_env_name"

 

Pod 디자인 패턴


파드 디자인패턴은 파드 내에 컨테이너를 어떻게 구성해서 실행할 것인지에 대한 설계도를 의미한다.  파드가 2개 이상의 컨테이너로 이루어져있기 때문에, 여러 파드가 있거나 의존성이 어떤지에 따라서 구성이 각가 다를 수 있다. 크게는 1) 사이드카(Side car), 2) 엠베서더(Ambassador), 3) 어뎁터(Adaptor) 패턴이 있다. 자세한 내용은 여기서도 확인할 수 있다.

1) 사이드 카 패턴: 사이드카는 아래의 그림과 같이 오토바이에 옆에 타는 부분을 의미한다. 사이드 카라는 의미는 여기서 가져왔다. 사이드카 패턴은 이미 기능적으로 잘 실행 될 수 있는 컨테이너에 뭔가 기능을 덧댄(Add on) 이미지 패턴을 의미한다. 본디 실행하고자하는 컨테이너 자체가 잘 동작하는 경우를 의미한다. 주로 로그를 쌓거나, 모니터링하는 기능을 더해서 사용하기도한다. 

Side car

2) 엠베서더(Ambassodor): 파드 외부와 내부를 연결해주는 역할을하는 것이다. 엠베서더는 대사를 의미한다. 외교사절단 대표정도로 의미가되는데, 쿠버네티스에서는 외부 TCP-Proxy로 DB을 연결해주는 역할을할수 있다. 주로 로드밸런서 역할을

3) 어뎁터 패턴(Adaptor): 어뎁터패턴은 어뎁터 용도의 컨테이너가 있어서, 각 컨테이너에서 생성하는 정보들을 모아서 관리해주거나, 또는 실제 물리적 DB에 인터페이스해서(또는 외부 데이터를 가져오는 역할), 어플리케이션에 다시 전달해주거나 해주는 역할로 사용된다. 가령 A, B, C 어플리케이션(각 컨테이너)의 로그가 제각각으로 저장되면, 이를 전처리해서 모아주는 역할을 하는 컨테이너가 있으면, 이 컨테이너가 어뎁터가 된다.

반응형

+ Recent posts