ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 11. 애플리케이션 스케줄링과 라이프사이클 관리 (1)
    개발 스터디/데브옵스(DevOps)를 위한 쿠버네티스 마스터 2021. 8. 17. 07:09
    반응형

    이 문서는 인프런 강의 "데브옵스를 위한 쿠버네티스 마스터"을 듣고 작성되었습니다. 최대한 요약해서 강의 내용을 최소로 하는데 목표를 두고 있어서, 더 친절하고 정확한 내용을 원하신다면 강의를 구매하시는 것을 추천드립니다. => 강의 링크

    컨테이너 환경 변수 전달 (1) YAML

    k8s에서 Pod에 실행되는 컨테이너에 환경 변수를 전달하는 방법은 크게 3가지가 있다.

    1. Yaml 파일에 직접 명시 "spec.containers[*].env"
    2. Secret
    3. ConfigMap

    이 절에서는 이 중 첫 번째 Yaml로 전달하는 방식을 알아본다. env-yaml.yaml을 다음과 같이 생성한다.

     

    src/ch11/k8s/env-yaml.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: env-yaml-mysql
    spec:
      containers:
        - image: mysql:5.6
          name: mysql
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: root

     

    spec.containers[*].env 형식으로 키 이름과 값을 전달한 것을 확인할 수 있다. 이제 터미널에 다음을 입려하여 리소스를 생성한다.

    $ kubectl create -f env-yaml.yaml 
    pod/env-yaml-mysql created
    
    $ kubectl get pod -w
    NAME             READY   STATUS    RESTARTS   AGE
    env-yaml-mysql   1/1     Running   0          4s

     

    이제 mysql 컨테이너에 다음 명령어를 입력하여, 로그인해보자. 비밀번호는 "root"이다.

    $ kubectl exec -it env-yaml-mysql -- mysql -u root -p
    Enter password: # root 입력

     

    성공적으로 로그인되었다면 다음 글을 확인할 수 있다.

    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 3
    Server version: 5.6.51 MySQL Community Server (GPL)
    
    Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
    
    Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
    mysql>

    컨테이너 환경 변수 전달 (2) Secret

    k8s에서 Pod에 실행되는 컨테이너에 환경 변수를 전달하는 방법은 크게 3가지가 있다.

    1. Yaml 파일에 직접 명시 "spec.containers[*].env"
    2. Secret
    3. ConfigMap

    이 절에서는 이 중 두 번째 Secret 리소스를 생성하여 값을 전달하는 방식을 알아본다. env-secret.yaml을 다음과 같이 생성한다.

     

    src/ch11/k8s/env-secret.yaml

    apiVersion: v1
    kind: Secret
    metadata:
      name: env-secret
    type: Opaque
    data:
      MYSQL_ROOT_PASSWORD: cm9vdA==
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: env-secret-mysql
    spec:
      containers:
        - image: mysql:5.6
          name: mysql
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: env-secret
                  key: MYSQL_ROOT_PASSWORD

     

    먼저 Secret 리소스를 생성하는 부분을 살펴보자.

    apiVersion: v1
    kind: Secret
    metadata:
      name: env-secret
    type: Opaque
    data:
      MYSQL_ROOT_PASSWORD: cm9vdA== # root를 인코딩한 값

     

    타 리소스 생성할 때와 별로 다를게 없다. 같은 네임스페이스 안의 다른 리소스들이 참조할 수 있도록 metadata.name을 지정해준다. 그 후 data에서 해당 키 이름과 원하는 값을 인코딩한 값을 설정해주면 된다. 리눅스 계열이라면 다음과 같이 쉽게 인코딩할 수 있다.

    # echo -n <원하는 값>|base64
    $ echo -n root|base64
    cm9vdA==

    참고! data, stringData
    "Secret"에서는 인코딩해서 data 필드에 키-값을 할당하는 것이 일반적이다. 하지만 그냥 평문을 전달하고 싶다면 stringData 필드를 쓰면 된다.

     

    Secret 리소스를 지정했으면 Pod 내부의 Container들이 이용하게 하려면 spec.containers[*].env[*].valueFrom.secretKeyRef로 지정하면 된다.

    apiVersion: v1
    kind: Pod
    metadata:
      name: env-secret-mysql
    spec:
      containers:
        - image: mysql:5.6
          name: mysql
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: env-secret          # 참조하는 Secret 이름
                  key: MYSQL_ROOT_PASSWORD  # Secret 내부의 키

     

    이제 다음 명령어를 통해서 리소스를 생성한다.

    $ kubectl create -f env-secret.yaml 
    secret/env-secret created
    pod/env-secret-mysql created
    
    $ kubectl get pod -w
    NAME               READY   STATUS    RESTARTS   AGE
    env-secret-mysql   1/1     Running   0          4s

     

    리소스가 생성되었다면 생성된 Secret을 다음 명령어로 확인해보자.

    $ kubectl get secret
    NAME                  TYPE                                  DATA   AGE
    default-token-xs7mw   kubernetes.io/service-account-token   3      4d22h
    env-secret            Opaque                                1      89s
    
    $ kubectl describe secret env-secret
    Name:         env-secret
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    
    Type:  Opaque
    
    Data
    ====
    MYSQL_ROOT_PASSWORD:  4 bytes

     

    이제 mysql 컨테이너에 다음 명령어를 입력하여, 로그인해보자. 비밀번호는 "root"이다.

    $ kubectl exec -it env-secret-mysql -- mysql -u root -p
    Enter password: # root 입력

     

    성공적으로 로그인되었다면 다음 글을 확인할 수 있다.

    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 3
    Server version: 5.6.51 MySQL Community Server (GPL)
    
    Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
    
    Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
    mysql>

    컨테이너 환경 변수 전달 (3) ConfigMap

    k8s에서 Pod에 실행되는 컨테이너에 환경 변수를 전달하는 방법은 크게 3가지가 있다.

    1. Yaml 파일에 직접 명시 "spec.containers[*].env"
    2. Secret
    3. ConfigMap

    이 절에서는 이 중 세 번째 ConfigMap 리소스를 생성하여 값을 전달하는 방식을 알아본다. env-configmap.yaml을 다음과 같이 생성한다.

     

    src/ch11/k8s/env-configmap-was.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: env-configmap-was
    spec:
      ports:
        - port: 8080
          targetPort: 8080
      selector:
        name: env-configmap-was
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: env-configmap-was
    spec:
      selector:
        matchLabels:
          name: env-configmap-was
      replicas: 3
      template:
        metadata:
          labels:
            name: env-configmap-was
        spec:
          containers:
            - name: env-configmap-was
              image: gcr.io/google-samples/node-hello:1.0
              ports:
                - containerPort: 8080
                  protocol: TCP
              env:
                - name: DEMO_GREETING
                  valueFrom:
                    configMapKeyRef:
                      name: env-configmap-was
                      key: DEMO_GREETING
                - name: DEMO_FAREWELL
                  valueFrom:
                    configMapKeyRef:
                      name: env-configmap-was
                      key: DEMO_FAREWELL
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: env-configmap-was
    data:
      DEMO_GREETING: "Hello from the environment with ConfigMap"
      DEMO_FAREWELL: "Hi Firewall"

     

    ConfigMap은 다음과 같이 쉽게 생성할 수 있다.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: env-configmap-was
    data:
      DEMO_GREETING: "Hello from the environment with ConfigMap"
      DEMO_FAREWELL: "Hi Firewall"

     

    Secret과 거의 유사한데, Secret과 달리 평문으로 전달되는게 ConfigMap이라고 생각하면 된다. 이렇게 생성된 키-값 쌍은 다음과 같이 불러서 사용하면 된다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: env-configmap-was
    spec:
      # ...
      template:
        # ...
        spec:
          containers:
            - name: env-configmap-was
              image: gcr.io/google-samples/node-hello:1.0
              ports:
                - containerPort: 8080
                  protocol: TCP
              env:
              - name: DEMO_GREETING
                valueFrom:
                  configMapKeyRef:
                    name: env-configmap-was
                    key: DEMO_GREETING
              - name: DEMO_FAREWELL
                valueFrom:
                  configMapKeyRef:
                    name: env-configmap-was
                    key: DEMO_FAREWELL

     

    Secret의 값을 불러 올 때 secretKeyRef으로 불러온 것처럼 ConfigMap의 값을 불러 올 때는 configMapKeyRef를 사용하면 된다. 이제 리소스를 생성해보자.

    $ kubectl create -f env-configmap-was.yaml
    service/env-configmap-was created
    deployment.apps/env-configmap-was created
    configmap/env-configmap-was created
    
    $  kubectl get pod -w
    NAME                                 READY   STATUS              RESTARTS   AGE
    env-configmap-was-77b58fc975-k6s79   0/1     ContainerCreating   0          6s
    env-configmap-was-77b58fc975-nvtjr   0/1     ContainerCreating   0          6s
    env-configmap-was-77b58fc975-rngql   0/1     ContainerCreating   0          6s
    env-configmap-was-77b58fc975-k6s79   1/1     Running             0          31s
    env-configmap-was-77b58fc975-nvtjr   1/1     Running             0          32s
    env-configmap-was-77b58fc975-rngql   1/1     Running             0          32s 

     

    Pod이 모두 생성되면 적당한 것을 골라서 다음 명령어를 입력해보자.

    # 환경 변수 초기화 확인
    $ kubectl exec -it env-configmap-was-77b58fc975-nvtjr -- printenv | grep "DEMO"
    DEMO_GREETING=Hello from the environment with ConfigMap
    DEMO_FAREWELL=Hi Firewall
    
    # 서비스 연결 테스트
    $  kubectl exec -it env-configmap-was-77b58fc975-nvtjr -- curl env-configmap-was:8080
    Hello Kubernetes!

     

    우리가 전달한 환경 변수가 잘 전달된 것을 확인할 수 있다. ConfigMap은 또한 볼륨으로써 Pod의 컨테이너들에게 부착될 수 있다. 예를 들어서 설정 파일 같은 것을 ConfigMap으로 만들어서 컨테이너의 볼륨에 올릴 수 있다. 다음과 같이 env-configmap-web.yaml을 생성한다.

     

    src/ch11/k8s/env-configmap-web.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: env-configmap-web
    spec:
      ports:
        - port: 80
          targetPort: 80
      selector:
        name: env-configmap-web
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: env-configmap-web
    spec:
      selector:
        matchLabels:
          name: env-configmap-web
      replicas: 3
      template:
        metadata:
          labels:
            name: env-configmap-web
        spec:
          containers:
            - name: env-configmap-web
              image: nginx
              ports:
                - containerPort: 80
                  protocol: TCP
              volumeMounts:
                - name: nginx
                  subPath: nginx.conf
                  mountPath: /etc/nginx/nginx.conf
                  readOnly: true
          volumes:
            - name: nginx
              configMap:
                name: env-configmap-web
                items:
                  - key: nginx.conf
                    path: nginx.conf
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: env-configmap-web
    data:
      nginx.conf: |
        error_log  /var/log/nginx/error.log warn;
        pid        /tmp/nginx.pid;
        worker_rlimit_nofile 8192;
    
        events {
            worker_connections  4096;  ## Default: 1024
        }
    
        http {
            default_type  application/octet-stream;
            log_format  main  '$remote_addr - $remote_user [$time_local] '
                              '"$request" $status $body_bytes_sent '
                              '"$http_referer" "$http_user_agent" "$request_time"';
    
            access_log  /var/log/nginx/access.log  main;
            sendfile        on;
            tcp_nopush     on;
    
            server {
                listen 80;
    
                location  / {
                    proxy_pass       http://env-configmap-was:8080;
                }
            }
        }

     

    ConfigMap.data 부분에서 "|" 밑으로 설정 파일을 만들었다. 이를 설정 파일로 취급하여 볼륨으로 마운트할 수 있다.

    kind: Deployment
    metadata:
      name: env-configmap-web
    spec:
      # ...
        spec:
          containers:
            - name: env-configmap-web
              # ...
              volumeMounts:
                - name: nginx
                  subPath: nginx.conf # items[*].path와 같아야 한다.
                  mountPath: /etc/nginx/nginx.conf
                  readOnly: true
          volumes:
            - name: nginx
              configMap:
                name: env-configmap-web # ConfigMap 이름
                items:
                  - key: nginx.conf     # ConfigMap에서 가져올 key와 같아야 한다.
                    path: nginx.conf

     

    이제 이 리소스들을 생성해보자.

    $ kubectl create -f env-configmap-web.yaml
    service/env-configmap-web created
    deployment.apps/env-configmap-web created
    configmap/env-configmap-web created
    
    $ kubectl get pod -w
    NAME                                 READY   STATUS    RESTARTS   AGE
    ...
    env-configmap-web-79fdfc5c8b-dr45r   1/1     Running   0          19s
    env-configmap-web-79fdfc5c8b-fbqkf   1/1     Running   0          19s
    env-configmap-web-79fdfc5c8b-wqx5z   1/1     Running   0          19s

     

    그 후 하나의 Pod을 골라 /etc/nginx/nginx.confConfigMap이 마운트 되었는지 확인해보자.

    $ kubectl exec -it env-configmap-web-79fdfc5c8b-wqx5z -- cat /etc/nginx/nginx.conf
    error_log  /var/log/nginx/error.log warn;
    pid        /tmp/nginx.pid;
    worker_rlimit_nofile 8192;
    
    events {
        worker_connections  4096;  ## Default: 1024
    }
    
    http {
        default_type  application/octet-stream;
        log_format  main  '$remote_addr - $remote_user [$time_local] '
                          '"$request" $status $body_bytes_sent '
                          '"$http_referer" "$http_user_agent" "$request_time"';
    
        access_log  /var/log/nginx/access.log  main;
        sendfile        on;
        tcp_nopush     on;
    
        server {
            listen 80;
    
            location  / {
                proxy_pass       http://env-configmap-was:8080;
            }
        }
    }

     

    잘 연결되었다면, Serviceenv-configmap-web을 호출하면 upstream 설정을 통해서 env-configmap-was:8080에게 전달되어서 다음 메세지가 보이게 될 것이다.

    $ kubectl exec -it env-configmap-web-79fdfc5c8b-wqx5z -- curl env-configmap-web
    Hello Kubernetes!

    한 개의 Pod, 여러 개의 컨테이너

    이전에 언급했듯이 한 개의 Pod에 여러 컨테이너를 실행하게 할 수 있다. 권장되는 구조는 아니며 보통 해당 컨테이너의 리소스를 모니터링하기 위해서 이런 구조를 취한다.

     

    이를 테면, NGINX의 액세스 로그를 파싱하여 상태 코드, 응답 시간 등에 대한 지표를 제공해야 할 때가 있다. 이 때 nginx 컨테이너와 함께 액세스 로그를 저장할 볼륨과 이 볼륨을 파싱해서 메트릭을 노출시키는 prometheus-nginxlog-exporter를 "SideCar" 형태로 제공하면 훌륭하게 이를 모니터링할 수 있다.

     

    다음과 같이 one-pod-multi-container.yaml을 생성한다.

     

    src/ch11/k8s/one-pod-multi-container.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: one-pod-multi-container
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80
              protocol: TCP
          volumeMounts:
            - mountPath: /var/log/nginx/
              name: accesslog
        - name: prometheus-nginxlog-exporter
          image: quay.io/martinhelmich/prometheus-nginxlog-exporter
          ports:
            - containerPort: 4040
              protocol: TCP
          volumeMounts:
            - mountPath: /var/log/nginx/
              name: accesslog
              readOnly: true
            - mountPath: /etc/prometheus-nginxlog-exporter.yml
              name: exporter
              subPath: prometheus-nginxlog-exporter.yaml
              readOnly: true
          command: ["/prometheus-nginxlog-exporter", "-config-file", "/etc/prometheus-nginxlog-exporter.yml"]
      volumes:
        - name: accesslog
          emptyDir: {}
        - name: exporter
          configMap:
            name: one-pod-multi-container
            items:
              - key: prometheus-nginxlog-exporter.yaml
                path: prometheus-nginxlog-exporter.yaml
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: one-pod-multi-container
    data:
      prometheus-nginxlog-exporter.yaml: |
        listen:
          port: 4040
          metrics_endpoint: "/metrics"
    
        consul:
          enable: false
    
        namespaces:
          - name: nginx
            format: "$remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" \"$request_time\""
            source:
              files:
                - /var/log/nginx/access.log
            only_count: true
            relabel_configs:
            - target_label: request_uri
              from: request
              split: 2
              separator: ' '

     

    위에처럼 1개의 Pod의 여러 개의 Container를 설정할 수 있다.

    apiVersion: v1
    kind: Pod
    metadata:
      name: one-pod-multi-container
    spec:
      containers:
        - name: nginx
          # ...
        - name: prometheus-nginxlog-exporter
          # ...

     

    nginxaccesslog라는 볼륨과 prometheus-nginxlog-exporteraccesslog, exporter라는 볼륨과 연결된다. exporterConfigMap과 연결된 설정 파일이다. 결과적으로 이 2개의 컨테이너는 accesslog라는 볼륨을 공유하게 된다.

     

    이제 다음 명령어를 이용하여 리소스를 생성해보자.

    $  kubectl create -f one-pod-multi-container.yaml
    pod/one-pod-multi-container created
    configmap/one-pod-multi-container created
    
    $ kubectl get pod
    # READY가 2/2가 되야 실행이 된것이다.
    NAME                      READY   STATUS    RESTARTS   AGE
    one-pod-multi-container   2/2     Running   0          16s

     

    그 후 터미널에 다음을 입력해보자.

    $ kubectl exec -it one-pod-multi-container -- curl localhost:4040/metrics
    Defaulted container "nginx" out of: nginx, prometheus-nginxlog-exporter
    # HELP nginx_parse_errors_total Total number of log file lines that could not be parsed
    # TYPE nginx_parse_errors_total counter
    nginx_parse_errors_total 0

     

    원래 nginx 컨테이너는 4040번 포트에 아무것도 연결되지 않기 때문에 "connection refused" 에러가 떠야 정상이지만 현재 Pod에는 prometheus-nginxlog-exporter라는 컨테이너가 같이 실행되고 있으므로 에러는 뜨지 않는다. 현재 발생된 로그가 없기 때문에 메트릭은 수집된 것이 없다. 메트릭 수집을 위해 다음을 입력해보자.

    $ for i in {1..5}; do kubectl exec -it one-pod-multi-container -- curl localhost; done

     

    이렇게 하면 nginx를 총 5번 호출하는 것과 같다. 먼저 볼륨에 로그 파일이 생성되었는지 확인해보자.

    $ kubectl exec -it one-pod-multi-container -- cat /var/log/nginx/access.log
    Defaulted container "nginx" out of: nginx, prometheus-nginxlog-exporter
    ::1 - - [16/Aug/2021:11:22:17 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.64.0" "-"
    ::1 - - [16/Aug/2021:11:22:17 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.64.0" "-"
    ::1 - - [16/Aug/2021:11:22:18 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.64.0" "-"
    ::1 - - [16/Aug/2021:11:22:18 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.64.0" "-"
    ::1 - - [16/Aug/2021:11:22:19 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.64.0" "-"

     

    액세스 로그가 생성되었다. prometheus-nginxlog-exporter가 이를 파싱해서 메트릭을 토축히키는지 확인해보자.

    $ kubectl exec -it one-pod-multi-container -- curl localhost:4040/metrics
    Defaulted container "nginx" out of: nginx, prometheus-nginxlog-exporter
    # HELP nginx_http_response_count_total Amount of processed HTTP requests
    # TYPE nginx_http_response_count_total counter
    nginx_http_response_count_total{method="GET",request_uri="/",status="200"} 5
    # HELP nginx_http_response_size_bytes Total amount of transferred bytes
    # TYPE nginx_http_response_size_bytes counter
    nginx_http_response_size_bytes{method="GET",request_uri="/",status="200"} 3060
    # HELP nginx_parse_errors_total Total number of log file lines that could not be parsed
    # TYPE nginx_parse_errors_total counter
    nginx_parse_errors_total 0

    이전과 다른 출력문을 확인할 수 있으며 nginx_http_response_count_total가 5개 수집된 것을 알 수 있다.

    초기 명령어 및 아규먼트 전달

    Docker에서 실행 시 초기 명령어 및 아규먼트 전달이 가능했다. 이미 지난 절을 진행하면서 Podcommand를 주어 초기 명령어 실행을 전달하는 것을 확인할 수 있었다.

    apiVersion: v1
    kind: Pod
    metadata:
      name: one-pod-multi-container
    spec:
      containers:
        - name: nginx
          # ...
        - name: prometheus-nginxlog-exporter
          # ...
          command: ["/prometheus-nginxlog-exporter", "-config-file", "/etc/prometheus-nginxlog-exporter.yml"]

     

    prometheus-nginxlog-exporter 포드는 실행 시 다음 명령어가 실행된다.

    $ /prometheus-nginxlog-exporter -config-file /etc/prometheus-nginxlog-exporter.yml

     

    단순 명령어만 실행하는 것도 가능하지만 args를 이용해 아규먼트 전달해서 명령어를 실행하는 것도 가능하다. command-args.yaml을 다음과 같이 만들어보자.

     

    src/ch11/k8s/command-args.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: command-args
    spec:
      containers:
        - name: command-args
          image: debian
          command: ["printenv"]
          args: ["HOSTNAME", "KUBERNETES_PORT"]
      restartPolicy: OnFailure

     

    요령은 간단하다. spec.containers[*] 블록 밑에 commandargs를 정의해주면 된다. 위의 Pod은 생성되면 다음 명령어를 실행한다고 보면 된다.

    $ printenv HOSTNAME KUBERNETES_PORT

     

    이제 리소스를 생성해보자.

    $ kubectl create -f command-args.yaml
    pod/command-args created
    
    $  kubectl get pod -w
    NAME           READY   STATUS              RESTARTS   AGE
    command-args   0/1     ContainerCreating   0          5s
    command-args   0/1     Completed           0          7s

     

    debian 이미지는 리눅스 그 자체이기 때문에 컨테이너를 유지시키는 명령어 없이는 Pod가 유지되지 않는다. 계획대로면 단순히 명령어만 실행하고 종료되기 때문에 "Completed" 상태가 됐다면 컨테이너가 정상적으로 종료된 것으로 보면 된다. 이제 한 번 로그를 확인해보자.

    $ kubectl logs command-args
    command-args         # HOSTNAME
    tcp://10.24.0.1:443  # KUBERNETES_PORT

     

    이런 비슷한 모양이 나왔다면 성공이다.

    init 컨테이너

    k8s에서는 InitContainer라는 특별한 목적을 지닌 컨테이너를 실행할 수 있다. 이 녀석은 Pod의 앱 컨테이너들이 실행되기 전에 실행되는 특수한 컨테이너이며, 앱 이미지에는 없는 유틸리티 또는 설정 스크립트 등을 포함할 수 있다. 한 번 해보자. init-container.yaml을 다음과 같이 만든다.

     

    src/ch11/k8s/init-container.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: init-container
    spec:
      ports:
        - port: 80
          targetPort: 80
      selector:
        name: init-container
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: init-container
    spec:
      selector:
        matchLabels:
          name: init-container
      replicas: 3
      template:
        metadata:
          labels:
            name: init-container
        spec:
          initContainers:
            - name: init-container-busybox
              image: busybox:1.28
              command: [ 'sh', '-c', "until nslookup env-configmap-was; do echo waiting for env-configmap-was; sleep 2; done" ]
          containers:
            - name: init-container
              image: nginx
              ports:
                - containerPort: 80
                  protocol: TCP
              volumeMounts:
                - name: nginx
                  subPath: nginx.conf
                  mountPath: /etc/nginx/nginx.conf
                  readOnly: true
          volumes:
            - name: nginx
              configMap:
                name: init-container
                items:
                  - key: nginx.conf
                    path: nginx.conf
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: init-container
    data:
      nginx.conf: |
        error_log  /var/log/nginx/error.log warn;
        pid        /tmp/nginx.pid;
        worker_rlimit_nofile 8192;
    
        events {
            worker_connections  4096;  ## Default: 1024
        }
    
        http {
            default_type  application/octet-stream;
            log_format  main  '$remote_addr - $remote_user [$time_local] '
                              '"$request" $status $body_bytes_sent '
                              '"$http_referer" "$http_user_agent" "$request_time"';
    
            access_log  /var/log/nginx/access.log  main;
            sendfile        on;
            tcp_nopush     on;
    
            server {
                listen 80;
    
                location  / {
                    proxy_pass       http://env-configmap-was:8080;
                }
            }
        }

     

    Init ContainerPodspec.initContainers에서 설정한다. 작성 요령은 spec.containers와 동일하다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: init-container
    spec:
      # ReplicaSet
        # POD
        spec:
          initContainers:
            - name: init-container-busybox
              image: busybox:1.28
              command: [ 'sh', '-c', "until nslookup env-configmap-was; do echo waiting for env-configmap-was; sleep 2; done" ]
          containers:
          # ...

     

    위 리소스는 env-configmap-web이랑 동일한 리소스를 생성한다. 거기에 Init Container를 이용하여 env-configmap-was 서비스가 실행되기 전까지 Pod 생성을 기다리는 부분을 추가했다. 이제 리소스를 생성해보자.

    $ kubectl create -f init-container.yaml
    service/init-container created
    deployment.apps/init-container created
    configmap/init-container created
    
    $ kubectl get pod -w
    NAME                              READY   STATUS     RESTARTS   AGE
    init-container-6646dd9cc8-njpzk   0/1     Init:0/1   0          26s
    init-container-6646dd9cc8-p4zmf   0/1     Init:0/1   0          26s
    init-container-6646dd9cc8-s62f7   0/1     Init:0/1   0          26s

     

    위 처럼 STATUS가 "Init:0/1" 상태로 유지되는 것을 확인할 수 있다. env-configmap-was라는 서비스가 존재하지 않기 때문이다.(매 2초마다 nslookup 명령어로 서비스를 찾는다.) 해당 서비스를 생성해보자.

    $ kubectl create -f env-configmap-was.yaml
    service/env-configmap-was created
    deployment.apps/env-configmap-was created
    configmap/env-configmap-was created

     

    다시 한 번 Pod의 상태를 확인한다.

    $ kubectl get pod -w
    NAME                                READY   STATUS    RESTARTS   AGE
    ...
    # 상태가 "RUNNING"으로 변경됨
    init-container-6646dd9cc8-njpzk     1/1     Running   0          89s
    init-container-6646dd9cc8-p4zmf     1/1     Running   0          89s
    init-container-6646dd9cc8-s62f7     1/1     Running   0          89s

     

    이제 init-container 포드들이 실행되는 것을 확인할 수 있다.

Designed by Tistory.