Browsing Tag

k8s

AWS

[AWS] EKS Fargate Logging Setting – Sharing failure experiences

안녕하세요. ManVSCloud 김수현입니다.

09월 12일 AKOS(AWS Kubernetes Online Study)가 마무리되었습니다.
CloudNet@ 가시다님과 2021년도에 ANOS, DKOS, AKOS 총 3회의 스터디를 진행했습니다.

다시 한 번 가시다님에게 감사의 인사 올립니다.
이번 포스팅은 AKOS의 졸업 과제를 포스팅 해보았습니다.


Fargate logging

Fargate logging 설정을 해보았습니다.

우선 결과적으로는 실패했습니다.
아래 방식대로 진행하는데에 있어 로그를 중앙 집중화할 때 CloudWatch와 결합하여 사용할 AWS용 Fluent Bit에 대해 자세히 몰랐기 때문이라 해당 포스팅 이후 Fluent Bit에 대해 추가적인 공부를 한 뒤 성공시킬 것입니다.

우선 Fagate 프로필은 이미 생성된 상태로 진행했습니다.

먼저 로그 라우터를 구성하기 위해 아래 .yaml 파일을 생성하였습니다.

vi fp-demo.yaml

kind: Namespace
apiVersion: v1
metadata:
  name: fp-demo
  labels:
    aws-observability: enabled
(aks-user@myeks:default) [root@myeks-host ~]# kubectl apply -f fp-demo.yaml
namespace/fp-demo created
(aks-user@myeks:default) [root@myeks-host ~]# kubens fp-demo
Context "aks-user@myeks.ap-northeast-2.eksctl.io" modified.
Active namespace is "fp-demo".
(aks-user@myeks:fp-demo) [root@myeks-host ~]# 

cloudwatch_logs 플러그인을 사용하기 위해 아래와 같은 .yaml도 생성해주었습니다.

vi aws-logging-cloudwatch.yaml

kind: ConfigMap
apiVersion: v1
metadata:
  name: aws-logging
  namespace: fp-demo
data:
  output.conf: |
    [OUTPUT]
        Name cloudwatch_logs
        Match   *
        region ap-northeast-2
        log_group_name fluent-bit-cloudwatch
        log_stream_prefix from-fluent-bit-
        auto_create_group true

  parsers.conf: |
    [PARSER]
        Name crio
        Format Regex
        Regex ^(?<time>[^ ]+) (?<stream>stdout|stderr) (?<logtag>P|F) (?<log>.*)$
        Time_Key    time
        Time_Format %Y-%m-%dT%H:%M:%S.%L%z

  filters.conf: |
     [FILTER]
        Name parser
        Match *
        Key_name log
        Parser crio
        Reserve_Data On
        Preserve_Key On

이 부분을 생성해줄 때 namespace 와 region 부분을 자신에게 맞게 설정하는 것이 중요합니다.

(aks-user@myeks:fp-demo) [root@myeks-host ~]# kubectl apply -f aws-logging-cloudwatch.yaml
configmap/aws-logging created

이후 CloudWatch IAM에 적용할 권한을 curl로 가져왔습니다.

(aks-user@myeks:fp-demo) [root@myeks-host ~]# curl -o permissions.json https://raw.githubusercontent.com/aws-samples/amazon-eks-fluent-logging-examples/mainline/examples/fargate/cloudwatchlogs/permissions.json
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   215  100   215    0     0    637      0 --:--:-- --:--:-- --:--:--   636

위에서 받아온 파일을 이용하여 아래와 같이 정책을 생성하였습니다.

(aks-user@myeks:fp-demo) [root@myeks-host ~]# aws iam create-policy --policy-name eks-fargate-logging-policy --policy-document file://permissions.json

아래 명령어로 attach 해줍시다. 중요하게 넣어야할 부분은
“내 계정”, “위에서 생성한 정책”, “fagate role 이름” 정도인 것같습니다.

(aks-user@myeks:fp-demo) [root@myeks-host ~]# aws iam attach-role-policy \
>   --policy-arn arn:aws:iam::내계정:policy/eks-fargate-logging-policy \
>   --role-name 역할이름
내 계정
역할 이름

권한 부분을 마친 뒤 테스트를 위해 아래와 같이 pod를 하나 생성하였습니다.

nginx-pod.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-app
  namespace: fp-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - name: http
              containerPort: 80
(aks-user@myeks:fp-demo) [root@myeks-host ~]# kubectl apply -f nginx-pod.yaml
deployment.apps/sample-app created

pod 생성 이후 아래 명령어로 logging 부분을 확인해보려 했으나 정상적으로 logging에 관련된 event가 발견되지 않았습니다.

(aks-user@myeks:fp-demo) [root@myeks-host ~]# kubectl get pod
NAME                             READY   STATUS    RESTARTS   AGE
kube-ops-view-5557846b44-ghhx7   1/1     Running   0          7m14s
sample-app-86b8cc866b-8njpn      1/1     Running   0          13m
sample-app-86b8cc866b-gz4x2      1/1     Running   0          13m
sample-app-86b8cc866b-l7gvb      1/1     Running   0          13m
(aks-user@myeks:fp-demo) [root@myeks-host ~]# 
(aks-user@myeks:fp-demo) [root@myeks-host ~]# kubectl describe pod sample-app-86b8cc866b-8njpn
Name:         sample-app-86b8cc866b-8njpn
Namespace:    fp-demo
Priority:     0
Node:         ip-192-168-2-43.ap-northeast-2.compute.internal/192.168.2.43
Start Time:   Sun, 19 Sep 2021 21:53:01 +0900
Labels:       app=nginx
              pod-template-hash=86b8cc866b
Annotations:  kubernetes.io/psp: eks.privileged
Status:       Running
IP:           192.168.2.137
IPs:
  IP:           192.168.2.137
Controlled By:  ReplicaSet/sample-app-86b8cc866b
Containers:
  nginx:
    Container ID:   docker://a5176ad1add9dcf2fd024e577f9c7e8af51c74d63f0c435c387220cce55ebada
    Image:          nginx:latest
    Image ID:       docker-pullable://nginx@sha256:853b221d3341add7aaadf5f81dd088ea943ab9c918766e295321294b035f3f3e
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sun, 19 Sep 2021 21:53:05 +0900
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-mpdh4 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-mpdh4:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  13m   default-scheduler  Successfully assigned fp-demo/sample-app-86b8cc866b-8njpn to ip-192-168-2-43.ap-northeast-2.compute.internal
  Normal  Pulling    13m   kubelet            Pulling image "nginx:latest"
  Normal  Pulled     13m   kubelet            Successfully pulled image "nginx:latest" in 2.853770826s
  Normal  Created    13m   kubelet            Created container nginx
  Normal  Started    13m   kubelet            Started container nginx

이번 테스트는 실패했지만 추가적인 트러블 슈팅 이후 추가 포스팅 해보도록 하겠습니다.


Personal Comments

이번 졸업 과제는 바쁜 와중에 허겁지겁 하느라 고생을 한 것같습니다.
원래 다양한 주제를 고민했었는데 주말마저 당직이라 긴 시간을 투자하지 못해 아쉬움이 있습니다.

최근에 EKS Anywhere가 출시되어 이 부분을 졸업 과제로 해보는건 어떨까 생각했지만 VMware vSphere 사용하기도 애매하고 시간도 부족해 혹시라도 VMware vSphere를 사용하시는 분이 있다면 참고하여 테스트 해보시라고 아래에 링크를 남깁니다.

가시다님 한 해 스터디 준비하시느라 고생 많으셨습니다.
CloudNet@ 운영진분들에게 모두 감사의 인사드립니다.

긴 글 읽어주셔서 감사합니다.


Problems found

포스팅을 누르는 순간 실패한 원인을 찾은듯 합니다.

켜져있던 웹 창을 정리하던 중 helm chart 를 보자마자 뭔가 이상하다는 걸 알아챘습니다.
fagate logging인데 pod가 fagate로 동작하지 않는듯한?…

이후 포스팅은 이 부분을 해결하고 Fluent Bit에 대해 알아본 것을 공유하는 포스팅이 되겠네요.


IT/Linux/Kubernetes

[K8S] Study the Kubernetes command in preparation for the CKA

안녕하세요. ManVSCloud 김수현입니다.

요즘 CKA 자격증 준비로 꾸준히 Kubernetes 공부를 하고 있습니다.
CKA 시험은 아무래도 실습 시험이다보니 꾸준히 실습 환경에서 다양한 연습을 필요로 합니다.

오늘은 제가 요즘 공부하고 있는 Kubernetes의 명령어들과 CKA 공부법 및 링크(Docs) 모음을 공유하고자 합니다.


Kubectl 명령어

kubernetes에서 클러스터에 명령을 내리기 위해서는 우선적으로 kubectl 명령어가 익숙해져야합니다. 자주 사용되는 kubectl 명령어에 대해 간단히 알아보도록 하겠습니다.

그런데… 명령어가 아~~~주 많습니다. create 명령어를 공부하기 위해 docs에 들어가서 create페이지를 들어가면 아래 명령어처럼 별거 아닌듯이 나와있지만 스크롤을 아무리 내려도 create가 끝나지 않을 것입니다.

$ kubectl create -f FILENAME

좌측 카테고리를 다시 한 번 봤는데 숨겨진 리스트들이 나오더군요…

처음부터 다~ 외우지 않아도 됩니다.
자주 사용하다보면 자주 사용하는 것들은 손이 익히게 되는 것이니까요?

CKA 시험도 kubernetes.io docs를 볼 수 있게 해주기 때문에 명령어를 한번씩 사용해보고 특정 상황에 맞게 필요한 명령어를 찾아서 사용할 수만 있다면 크게 문제 없을 것이라 생각됩니다.

The most basic commands for importing workloads ?
  • create
  • get
  • run
  • expose
  • delete
APP MANAGEMENT ?
  • apply
  • annotate
  • autoscale
  • debug
  • diff
  • edit
  • kustomize
  • label
  • patch
  • replace
  • rollout
  • scale
  • set
  • wait
WORKING WITH APPS ?
  • attach
  • auth
  • cp
  • describe
  • exec
  • logs
  • port-forward
  • proxy
  • top
CLUSTER MANAGEMENT ?
  • api-versions
  • certificate
  • cluster-info
  • cordon
  • drain
  • taint
  • uncordon
KUBECTL SETTINGS AND USAGE ?
  • alpha
  • api-resources
  • completion
  • config
  • explain
  • options
  • plugin
  • version

CKA(Certified Kubernetes Administrator)를 제대로 준비하자!

우선 CKA를 준비하는 지금 docs에서 yaml 파일을 구해서 쓴다기보다 명령어를 이용하여 yaml 파일을 생성하는 연습을 하고 있습니다. 예를 들어봅시다.

네임스페이스는 manvscloud이고 레이블은 name=kim을 사용해야하는 1.12버전의 nginx를 생성조건에 맞게 명령어를 써본다면 아래와 같이 쓸 수 있습니다.

root@cka-k8s-master:/home/k8s# kubectl run nginx --image=nginx:1.12 --labels=name=kim --namespace=manvscloud --dry-run=client -o yaml > nginx.yaml

생성된 yaml 파일을 보면 아래와 같이 생성되어 있습니다.

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    name: kim
  name: nginx
  namespace: manvscloud
spec:
  containers:
  - image: nginx:1.12
    name: nginx
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

명령어로 yaml 생성에 익숙해진다면 yaml 파일을 생성하지 않고 옵션에 맞게 pod를 생성하는 것도 해봅니다.

root@cka-k8s-master:/home/k8s# kubectl run nginx --image=nginx:1.12 --labels=name=kim --namespace=manvscloud --dry-run=client -o yaml | kubectl create -n manvscloud -f -

이런 방법으로 연습을 해주면 명령어 옵션도 빠르게 익힐 수 있고 이후 yaml에 익숙하지 않더라도 어떠한 옵션을 넣어야하는데 어디에 넣어야할지 모를 때 명령어로 원하는 옵션을 주고 yaml 파일로 뽑아서 확인도 해볼 수 있을 것같습니다.


또 다른 주제로 Multi-container pod 환경에서 확인 방법에 대해서도 적응했습니다.
우선 예시로 Multi-container pod 하나를 생성하겠습니다.

vi multicon.yaml

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: multi-con
  name: multi-con
spec:
  containers:
  - image: nginx
    name: nginx-con
  - image: redis
    name: redis-con
  - image: mongo
    name: mongo-con
  restartPolicy: Always

하나의 pod 내에 3개의 컨테이너 이미지가 존재하는 것입니다.

root@cka-k8s-master:/home/k8s# kubectl get pod --show-labels
NAME        READY   STATUS    RESTARTS   AGE   LABELS
multi-con   3/3     Running   0          17m   run=multi-con

아래 명령어들로 컨테이너 이미지 목록을 볼 수 있습니다.

root@cka-k8s-master:/home/k8s# kubectl describe pod | grep Image
    Image:          nginx
    Image ID:       docker-pullable://nginx@sha256:353c20f74d9b6aee359f30e8e4f69c3d7eaea2f610681c4a95849a2fd7c497f9
    Image:          redis
    Image ID:       docker-pullable://redis@sha256:b6a9fc3535388a6fc04f3bdb83fb4d9d0b4ffd85e7609a6ff2f0f731427823e3
    Image:          mongo
    Image ID:       docker-pullable://mongo@sha256:fe44eb6a2ea2bb1548718ec05eb9cb165f1bded37595ebea507bddc413ab99ae

// 레이블이 run=multi-con으로 필터링된 컨테이너 이미지 목록
root@cka-k8s-master:/home/k8s# kubectl get pods --all-namespaces -o=jsonpath="{.items[*].spec.containers[*].image}" -l run=multi-con
nginx redis mongo

그렇다면 하나의 pod안에 다수의 컨테이너가 있다면 어떻게 다를까요?
-c 옵션으로 pod 내에 컨테이너를 지정하여 명령어를 사용하거나 해당 컨테이너로 접속이 가능합니다.

// nginx-con 컨테이너 내에 nginx.conf 파일 여부 확인
root@cka-k8s-master:/home/k8s# kubectl exec multi-con -c nginx-con -- ls -l /etc/nginx/nginx.conf
-rw-r--r-- 1 root root 648 Jul  6 15:11 /etc/nginx/nginx.conf

//mongo-con 컨테이너 접속
root@cka-k8s-master:/home/k8s# kubectl exec -it multi-con -c mongo-con -- /bin/bash
root@multi-con:/#

생각보다 간단하지만 이런 케이스를 경험해보지 않는다면 당황할 수 있으니 어떠한 케이스라도 한번씩 다 해보는 게 중요하다고 봅니다.
(이해하지 못하고 무작정 외우는 건 제가 선호하는 타입이 아니라서…)


마지막으로 하나를 더 알아보겠습니다.

이번에는 마스터의 kubectl, kubelet, kubeadm의 버전을 업그레이드 할 것입니다.
단, 작업 전 예약 불가능으로 설정할 것이며 작업 후 예약 가능하도록 설정해줄 것입니다.
또한 업그레이드 하기 전 유지 관리를 위해 마스터를 drain 해줄 것입니다.

작업 전 master에서 kubernetes 패키지를 확인해보니 현재 kubectl, kubelet, kubeadm 버전은 1.21.1이네요. 해당 버전을 1.21.2로 업그레이드 하겠습니다.

[root@manvscloud-k8s-m ~ (kube:default)]# dpkg -l | grep kube
hi  kubeadm                              1.21.1-00                         amd64        Kubernetes Cluster Bootstrapping Tool
hi  kubectl                              1.21.1-00                         amd64        Kubernetes Command Line Tool
hi  kubelet                              1.21.1-00                         amd64        Kubernetes Node Agent
ii  kubernetes-cni                       0.8.7-00                          amd64        Kubernetes CNI

업그레이드 전 조건이 있으니 우리는 kubectl 명령어 중 cordon, uncordon, drain 을 사용하게 됩니다.

// 아래와 같이 명령어를 사용해주면 해당 노드는 스케줄이 불가능하게 표시됩니다.
[root@manvscloud-k8s-m ~ (kube:default)]# kubectl cordon manvscloud-k8s-m
node/manvscloud-k8s-m cordoned

// 이제 drain을 해주는데 이는 유지 관리를 위해 지정된 노드에 있는 pod들을 다른곳으로 이동시키는 명령어입니다. 자세한 옵션은 kubectl docs를 참고해주세요.
[root@manvscloud-k8s-m ~ (kube:default)]# kubectl drain manvscloud-k8s-m --delete-local-data --ignore-daemonsets --force
Flag --delete-local-data has been deprecated, This option is deprecated and will be deleted. Use --delete-emptydir-data.
node/manvscloud-k8s-m already cordoned
WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-xqbt6, kube-system/kube-proxy-jqvxn
evicting pod kube-system/coredns-558bd4d5db-gv4dn
evicting pod kube-system/calico-kube-controllers-78d6f96c7b-5nnlh
evicting pod kube-system/coredns-558bd4d5db-62njr
pod/calico-kube-controllers-78d6f96c7b-5nnlh evicted
pod/coredns-558bd4d5db-gv4dn evicted
pod/coredns-558bd4d5db-62njr evicted
node/manvscloud-k8s-m evicted

// 이제 1.21.2 버전을 설치해줍시다.
[root@manvscloud-k8s-m ~ (kube:default)]# apt-get install kubeadm=1.21.2-00 kubelet=1.21.2-00 kubectl=1.21.2-00

--- 설치 내용 생략 ---

// 이후 daemon-reload와 kubelet을 재시작 해줍니다.
[root@manvscloud-k8s-m ~ (kube:default)]# systemctl daemon-reload
[root@manvscloud-k8s-m ~ (kube:default)]# systemctl restart kubelet

kubectl, kubelet, kubeadm의 버전이 1.21.2 버전으로 설치되었습니다.

[root@manvscloud-k8s-m ~ (kube:default)]# dpkg -l | grep kube
ii  kubeadm                              1.21.2-00                         amd64        Kubernetes Cluster Bootstrapping Tool
ii  kubectl                              1.21.2-00                         amd64        Kubernetes Command Line Tool
ii  kubelet                              1.21.2-00                         amd64        Kubernetes Node Agent
ii  kubernetes-cni                       0.8.7-00                          amd64        Kubernetes CNI

이제 마스터 노드가 정상적으로 스케줄 예약이 가능하도록 uncordon 해줍니다.

[root@manvscloud-k8s-m ~ (kube:default)]# kubectl uncordon manvscloud-k8s-m
node/manvscloud-k8s-m uncordoned

kubectl get nodes로 마스터 노드 버전을 보시면 마스터 노드의 버전이 1.21.2로 올라 가있는 것을 보실 수 있습니다.

[root@manvscloud-k8s-m ~ (kube:default)]# kubectl get nodes
NAME                STATUS   ROLES                  AGE   VERSION
manvscloud-k8s-m    Ready    control-plane,master   23d   v1.21.2
manvscloud-k8s-w1   Ready    <none>                 23d   v1.21.1
manvscloud-k8s-w2   Ready    <none>                 23d   v1.21.1
manvscloud-k8s-w3   Ready    <none>                 23d   v1.21.1

CKA(Certified Kubernetes Administrator) 공부 시 참고한 링크 모음


Personal Comments

지금까지 CKA 시험에 대비한 kubectl 명령어에 대해 간단하게 알아보았습니다.
다음 포스팅은 etcdctl 명령어로 CKA 공부를 이어서 진행해보도록 하겠습니다.

긴 글 읽어주셔서 감사합니다.

IT/Linux/Kubernetes

[K8S] CKA(Certified Kubernetes Administrator) Study 참고 링크 모음

안녕하세요. ManVSCloud 김수현입니다.

해당 포스팅은 CKA(Certified Kubernetes Administrator)를 공부하며 참고했던 링크들의 모아둔 글입니다.

이 포스팅은 CKA 시험 합격 포스팅이 올라오기 전까지 주기적으로 업데이트 됩니다.


※ A collection of links that have been referenced

? kubectl Commands Reference Docs


Personal Comments

이 포스팅은 주기적으로 업데이트되니 확인하실 때마다 링크가 추가될 수 있습니다.

읽어주셔서 감사합니다.

Certificate

CKA(Certified Kubernetes Administrator) 시험 일정

안녕하세요. ManVSCloud 김수현입니다.

드디어 미루어왔던 CKA(Certified Kubernetes Administrator) 시험 일정이 정해졌습니다.
2021-07-31 18:15~20:15에 시험이 예정되었습니다.

현재 DKOS에서 Kubernetes를 꾸준히 공부하고 있습니다.
다른 일정들도 많지만 이번달 말까지는 쿠버네티스 학습에 조금 더 비중을 두려고 합니다.

시험 합격 후 공부법과 시험을 어떻게 준비할 것인가에 대해 자세히 후기를 남기도록 하겠습니다.

NCP

[NCP] Container Registry에서 이미지를 가져오기 & 로드밸런서 연결

안녕하세요. ManVSCloud 김수현입니다.

오늘은 Naver Cloud Platform에서 Container Registry에서 이미지를 가져오는 방법과 Load Balancer에 연결하는 방법을 알아보도록 하겠습니다.


CONTAINER REGISTRY에서 이미지를 가져오기

아직 Container Registry를 생성해본 적이 없으시다면 위 [NAVER CLOUD KUBERNETES – CONTAINER REGISTRY로 컨테이너 이미지를 관리]를 먼저 보고 오시기 바랍니다.

위 포스팅에서는 push를 해보았습니다. 오늘은 pull을 해볼 시간입니다.

우선 테스트용으로 하고 계시다면 이전에 했던 docker image를 전부 지우고 한 번 해보도록합시다.

[root@kubernetes-server-kr2 ~]# docker rm `docker ps -a -q`
[root@kubernetes-server-kr2 ~]# docker rmi -f `docker images -q`

docker login을 해줍시다.

[root@kubernetes-server-kr2 ~]# docker login <CONTAINER REGISTRY에 나와있는 엔드포인트>
Authenticating with existing credentials...
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

docker pull 엔드포인트/이미지:버전 명령어로 docker 이미지를 가져올 수 있습니다.

[root@kubernetes-server-kr2 ~]# docker pull manvscloud-k8s-cr.kr.ncr.ntruss.com/manvscloud-apache:1.0
1.0: Pulling from manvscloud-apache
2d473b07cdd5: Pull complete 
444a3233aeea: Pull complete 
Digest: sha256:b2e60515712f6c5d4f155e9d234299fa82640d8dc7766405fe997c1b80658c07
Status: Downloaded newer image for manvscloud-k8s-cr.kr.ncr.ntruss.com/manvscloud-apache:1.0
manvscloud-k8s-cr.kr.ncr.ntruss.com/manvscloud-apache:1.0

또한 k8s에서 secret을 이용한다면 패스워드, OAuth 토큰, ssh 키와 같은 정보를 저장 및 관리할 수 있는데 이를 이용하여 pod를 생성해보도록 합시다.

[root@kubernetes-server-kr2 ~]# kubectl get secret
NAME                  TYPE                                  DATA   AGE
default-token-p5mq2   kubernetes.io/service-account-token   3      11d

kubectl create secret docker-registry “secret 이름” –docker-server=레지스트리-엔드포인트 –docker-username=Access-Key-ID –docker-password=Secret-Key –docker-email=계정으로 아래와 같이 secret을 만들 수 있습니다.

[root@kubernetes-server-kr2 ~]# kubectl create secret docker-registry manvscloud-sec --docker-server=레지스트리-엔드포인트 --docker-username=Access-Key-ID --docker-password=Secret-Key --docker-email=계정

[root@kubernetes-server-kr2 ~]# kubectl get secret
NAME                  TYPE                                  DATA   AGE
default-token-p5mq2   kubernetes.io/service-account-token   3      11d
manvscloud-sec        kubernetes.io/dockerconfigjson        1      19s

이제 yaml 파일을 생성하여 위에서 생성한 secret을 이용하여 이미지를 pull 및 pod 생성을 해봅시다.

vi apache.yaml

apiVersion: v1
kind: Pod
metadata:
 name: manvscloud-apache
 namespace: default
spec:
 containers:
 - name: manvscloud-apache
   image: manvscloud-k8s-cr.kr.ncr.ntruss.com/manvscloud-apache:1.0
 imagePullSecrets:
 - name: manvscloud-sec
[root@kubernetes-server-kr2 ~]# kubectl create -f apache.yaml 
pod/manvscloud-apache created

[root@kubernetes-server-kr2 ~]# kubectl get pods
NAME                                 READY   STATUS    RESTARTS   AGE
manvscloud-apache                    1/1     Running   0          4s

CONTAINER REGISTRY에 있는 이미지를 잘 가져와 pod가 생성되었습니다.
이렇게 CONTAINER REGISTRY를 이용하여 이미지 배포 관리가 쉽게 가능합시다.

또한 CONTAINER REGISTRY에서 Configuration을 클릭하여 Public Endpoint를 활성화/비활성화 선택이 가능합니다. 네이버 클라우드 내부에서만 사용할 것이라면 비활성화 하는 것이 좋습니다.


로드밸런서 연결

네이버 클라우드 Kubernetes Service를 사용중이라면 서비스 생성 시에 type을 LoadBalancer로 지정할 경우 네이버 클라우드 콘솔 내에 로드밸런서 인스턴스가 자동으로 생성됩니다.

로드밸런서 설정의 경우 어노테이션으로 설정할 수 있습니다.

"metadata": {
  "annotations": {
    "key1" : "value1",
    "key2" : "value2"
  }
}
https://guide.ncloud-docs.com/docs/nks-nks-1-8

실습을 통해 직접 로드밸런서를 생성해봅시다.
이번 실습에서는 어노테이션을 이용하여 추가적인 설정은 하지 않았습니다.
간단하게 로드밸런서 연결만 따라할 수 있도록 해두었습니다.

vi manvscloud-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
 name: apache-deployment
spec:
 replicas: 3
 selector:
   matchLabels:
     app: apache
 template:
   metadata:
     labels:
       app: apache
   spec:
     containers:
     - name: apache
       image: manvscloud-k8s-cr.kr.ncr.ntruss.com/manvscloud-apache:1.0
       ports:
       - containerPort: 80
     imagePullSecrets:
     - name: manvscloud-sec

아래와 같이 kubectl get pods –show-labels 했을 때 LABELS이 붙어있을 것입니다.
replicas, label 등은 따로 쿠버네티스에 대한 공부가 필요하니 이러한 설정에 이해가 어려우신 분들은 우선 kubernetes에 대한 공부를 우선적으로 간단하게나마 하시는 것을 권장드립니다.

[root@kubernetes-server-kr2 ~]# kubectl get pods --show-labels
NAME                                 READY   STATUS    RESTARTS   AGE   LABELS
apache-deployment-75895cbcbb-6dlvz   1/1     Running   0          14s   app=apache,pod-template-hash=75895cbcbb
apache-deployment-75895cbcbb-l7q4d   1/1     Running   0          14s   app=apache,pod-template-hash=75895cbcbb
apache-deployment-75895cbcbb-vcvpq   1/1     Running   0          14s   app=apache,pod-template-hash=75895cbcbb

[root@kubernetes-server-kr2 ~]# for pod in $(kubectl get pod -l app=apache |awk 'NR>1 {print $1}'); do kubectl exec $pod -- /bin/sh -c "hostname > /var/www/html/index.html; echo '안녕하세요. ManVSCloud입니다.' >> /var/www/html/index.html"; done

각 pod 내 index.html 파일을 수정해주었습니다.
로드밸런서를 연결하여 접속하기 위해 LoadBalancer를 생성해봅시다.

아래와 같이 Serivces yaml을 생성합니다.

vi lb.yaml

kind: Service
apiVersion: v1
metadata:
 name: lb-service
spec:
 ports:
   - port: 80
     targetPort: 80
 selector:
   app: apache
 type: LoadBalancer
[root@kubernetes-server-kr2 ~]# kubectl create -f lb.yaml 
service/lb-service created

kubectl get services 명령어로 확인해보면 EXTERNAL-IP가 NCP 내 LB로 되어있는 것을 확인할 수 있습니다.

[root@kubernetes-server-kr2 ~]# kubectl get services
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP                                                        PORT(S)        AGE
kubernetes   ClusterIP      198.19.128.1    <none>                                                             443/TCP        11d
lb-service   LoadBalancer   198.19.208.51   default-lb-service-821a9-7191539-4b535e410da7.kr.lb.naverncp.com   80:31033/TCP   5m33s

콘솔을 보면 따로 Load Balancer를 생성해주지 않았는데 따로 콘솔상에서 생성되어 있는 것을 확인할 수 있습니다. 삭제도 마찬가지입니다.
kubectl delete svc lb-service를 해주면 콘솔상에서도 자동 제거가 됩니다.

생성된 LB의 접속 정보를 이용하여 웹에서 접속해보면 위에서 추가해준 index.html의 값이 나오고 있습니다.

로드밸런싱 알고리즘은 기본값인 Round Robin으로 설정되어 있으며 Least Connection과 Source IP Hash로도 변경이 가능합니다.


Personal Comments

오늘은 CONTAINER REGISTRY에서 이미지를 가져오는 방법과 로드밸런싱 연동 방법을 알아보았습니다.

참고로 실습 과정을 따라해보실 경우 .yaml 파일을 그대로 복사하지 마시고 엔드포인트를 잘 수정하여 사용하시기 바랍니다.

긴 글 읽어주셔서 감사합니다.

함께 보며 공부하기 좋은 자료

NCP

[NCP] Naver CLoud Kubernetes – Container Registry로 컨테이너 이미지를 관리하자

안녕하세요. ManVSCloud 김수현입니다.

오늘은 이전 포스팅인 “[NCP] NAVER CLOUD에서 KUBERNETES를 사용해보자 – NKS“에 이어 컨테이너로 이미지를 관리하는 방법을 알아보도록 하겠습니다.


Object Storage 생성

Container Registry를 생성하기 전에 Object Storage가 먼저 생성되어야합니다.
Container Registry에 저장될 컨테이너 이미지는 Object Storage에 저장되기 때문입니다.

이후 Container Registry에 이미지를 저장하고 오브젝트 스토리지에 어떻게 저장되는지도 함께 보도록합시다.

Object Storage 생성은 어렵지 않습니다.
우선 버킷 이름을 적어주고 [다음]을 누릅시다. 참고로 버킷 이름은 유니크한 값으로 이름이 중복될 수 없습니다.

권한은 공개하지 않도록 해두고 계정 설정은 추가적으로 하지 않겠습니다.

버킷 하나가 쉽게 생성이 되었습니다.
Object Storage에 대해 자세히 알고 싶으시다면 아래 사용 가이드도 참고해보시기 바랍니다.


Container Registry 생성

Container Registry를 생성해보겠습니다.
Container Registry 를 이용하면 컨테이너 이미지를 쉽게 업로드 및 배포할 수 있습니다.

[이용 가이드]가 있어 사용하기 쉬운 편입니다.
아래에서 생성한 Container Registry로 이미지 업로드를 해볼 것입니다.


컨테이너 이미지(Dockerfile) 만들기

간단하게 Dockerfile을 만들어보도록 하겠습니다.

vi Dockerfile

FROM centos:7

RUN yum -y update && yum install -y httpd*
CMD ["systemctl","restart","httpd"]
CMD ["/usr/sbin/httpd","-D","FOREGROUND"]

위에서 생성한 이미지를 아래와 같이 빌드해줍시다.

[root@kubernetes-server-kr2 ~]# docker build -t manvscloud-apache .
Sending build context to Docker daemon  179.7kB
Step 1/4 : FROM centos:7
7: Pulling from library/centos
2d473b07cdd5: Pull complete 
Digest: sha256:0f4ec88e21daf75124b8a9e5ca03c37a5e937e0e108a255d890492430789b60e
Status: Downloaded newer image for centos:7
.
.
.
Complete!
Removing intermediate container 47ec6561ff67
 ---> 70b6f6999f0d
Step 3/4 : CMD ["systemctl","restart","httpd"]
 ---> Running in fa442e0e6f10
Removing intermediate container fa442e0e6f10
 ---> 8196868e79b0
Step 4/4 : CMD ["/usr/sbin/httpd","-D","FOREGROUND"]
 ---> Running in 0a08c642dcc6
Removing intermediate container 0a08c642dcc6
 ---> 2171dc304b08
Successfully built 2171dc304b08
Successfully tagged manvscloud-apache:latest

docker images 명령어로 확인해보면 빌드한 이미지를 확인하실 수 있습니다.
이제 빌드된 이미지를 run 해보도록합시다.

[root@kubernetes-server-kr2 ~]# docker images
REPOSITORY          TAG       IMAGE ID       CREATED          SIZE
manvscloud-apache   latest    2171dc304b08   17 seconds ago   517MB
centos              7         8652b9f0cb4c   7 months ago     204MB

[root@kubernetes-server-kr2 ~]# docker run -tid -p 8080:80 --name manvscloud-apache01 manvscloud-apache
0edc715160a959582dd085f54ec7c384d278648f5377c2cad15816f83a252c7d

[root@kubernetes-server-kr2 ~]# docker ps
CONTAINER ID   IMAGE               COMMAND                  CREATED         STATUS         PORTS                  NAMES
0edc715160a9   manvscloud-apache   "/usr/sbin/httpd -D …"   7 seconds ago   Up 6 seconds   0.0.0.0:8080->80/tcp   manvscloud-apache01

IP : 8080 또는 서버 내부에서는 curl localhost:8080 로 확인할 수 있습니다.

[root@kubernetes-server-kr2 ~]# netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      929/sshd            
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      593/rpcbind         
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      40020/docker-proxy  
tcp6       0      0 :::22                   :::*                    LISTEN      929/sshd            
tcp6       0      0 :::111                  :::*                    LISTEN      593/rpcbind  

이미지 업로드

이제 위에서 생성한 이미지를 Container Registry로 업로드 해보겠습니다.
Container Registry에 업로드 하기위해서 [마이페이지]-[인증키 관리]에서 미리 API 인증키를 생성 해놓으시기 바랍니다.

위에서 생성한 API 키를 이용하여 업로드를 해볼텐데
1) docker login -u [생성한 API Key ID] [생성한 Container Registry의 엔드포인트]를 입력한 후 API Key의 패스워드를 입력하여 로그인을 해줍니다.
2) 이후 docker image tag로 태그를 정해줍시다.
3) 마지막으로 docker push 명령어를 이용하여 아래와 같이 push 해줍니다.

[root@kubernetes-server-kr2 ~]# docker login -u [Access Key ID] manvscloud-k8s-cr.kr.ncr.ntruss.com
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

[root@kubernetes-server-kr2 ~]# docker image tag manvscloud-apache manvscloud-k8s-cr.kr.ncr.ntruss.com/manvscloud-apache:1.0

[root@kubernetes-server-kr2 ~]# docker push manvscloud-k8s-cr.kr.ncr.ntruss.com/manvscloud-apache:1.0
The push refers to repository [manvscloud-k8s-cr.kr.ncr.ntruss.com/manvscloud-apache]
d4208dd0734c: Pushed 
174f56854903: Pushed 
1.0: digest: sha256:b2e60515712f6c5d4f155e9d234299fa82640d8dc7766405fe997c1b80658c07 size: 742

아래 Container Registry가 보이시나요?
push했던 manvscloud-apache 이미지가 업로드 되었습니다.

Object Storage에 들어가서 해당 버킷으로 들어가보면 해당 이미지 파일이 저장되고 있는 것도 확인해볼 수 있습니다.


Personal Comments

요즘 컨테이너 환경을 사용하는 유저가 많이 늘었습니다.
저희 고객님들도 점점 컨테이너화된 어플리케이션 서비스를 구성하는 모습이 자주 보이기 시작합니다.

특히 다수의 컨테이너 사용자들은 퍼블릭 클라우드 환경에서 컨테이너 서비스를 운영중이며 요즘은 하이브리드 클라우드를 상당히 많이 보았습니다.
네이버 클라우드에서는 한국인이 쉽게 접근할 수 있도록 가이드들이 한글로 자세히 안내되고 있어 서비스들을 사용할 때 다른 플랫폼 보다 크게 부담이 느껴지지 않는 점이 가장 좋은 것같습니다.

긴 글 읽어주셔서 감사합니다.

NCP

[NCP] Naver CLoud에서 Kubernetes를 사용해보자 – NKS

안녕하세요. ManVSCloud 김수현입니다.

DKOS(Docker Kubernetes Online Study) 2주차 과정을 마쳤습니다.

가상 머신, 물리 서버, AWS, Azure 환경에서 k8s 클러스터를 배포하는 것을 스터디하였지만 Naver Cloud Platform에서 k8s 클러스터를 배포하는 방법은 따로 스터디 하지 않아 이에 대해 공유하고자 오늘은 네이버 클라우드에서 k8s 클러스터 배포와 사용에 대해 알아보도록 하겠습니다.


Classic

우선 Classic 환경에서는 현재 Kubernetes Service 사용이 불가능합니다.

2021년 03월 04일까지만 사용할 수 있었고 현재는 사용 불가능하므로 저는 VPC 환경에서 Kubernetes Service 사용법에 대해 써보도록 하겠습니다.


VPC – VPC & Subnet 생성

우선 Naver Cloud Platform에서 VPC 환경을 사용하시려면 VPC 생성하여 서브넷 구성을 해주셔야합니다. 기존 AWS나 Azure와 같은 퍼블릭 클라우드 사용 경험이 많으시다면 이를 구성하는데에 큰 어려움이 없으실 것이라 생각합니다.

저는 위 이미지와 같이 생성해주었습니다.
오늘 포스팅에서는 LB까지는 사용하지 않지만 Naver Cloud 에서 k8s 클러스터 배포 시 가장 기본이 되는 서브넷 구성이라고 볼 수 있겠습니다.


VPC – Server

우선 서버를 생성해줍니다.
해당 서버 내에서 이후 생성할 각 클러스터들을 컨트롤 해줄 것입니다.

OS는 CentOS나 Ubuntu 아무것이나 괜찮습니다.

해당 서버의 패스워드 확인 후 서버로 접속해줍니다.
이후 아래 명령어를 이용하여 kubectl과 docker를 설치해줍시다.

[root@kubernetes-server-kr2 ~]# cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF

가끔 gpgkey 부분을 엔터쳐서 다음 줄로 내려버리시는 경우가 있는데 정상 설치가 안되니 아래 이미지와 같이 되게 해주세요.

/etc/yum.repos.d/kubernetes.repo
[root@kubernetes-server-kr2 ~]# yum install -y kubectl

//yum-utils device-mapper-persistent-data lvm2는 이미 설치가 되어있어서 따로 설치해줄 필요가 없었습니다.

[root@kubernetes-server-kr2 ~]# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
[root@kubernetes-server-kr2 ~]# yum install -y docker-ce
[root@kubernetes-server-kr2 ~]# systemctl enable --now docker

VPC – NKS Cluster

이제 Kubernetes Service를 생성해줄 것입니다.

NKS 클러스터는 현재 1.17과 1.18 버전을 지원하고 있습니다.
또한 Pod Security Policy, Audit Log는 클러스터 생성 후에도 수정할 수 있으니 이후에 설정하셔도 됩니다.

생성 중에 NAT Gateway를 생성하라는 메시지가 발생합니다.
이는 왜 NAT Gateway를 생성해야하는지에 대해 아래 내용에서 보여드리기위해 따로 NAT Gateway를 먼저 설정해두지 않았습니다.

일단 넘어갑시다.

원하시는 서버 스펙과 노드 수를 정해준 뒤 추가해주면 클러스터가 생성됩니다.
해당 클러스터 생성에는 다소 시간이 소요됩니다.


VPC – Practice

이제 생성한 Server와 각 k8s 클러스터들을 이용하여 실습을 해보도록 하겠습니다.
우선 Server에서 생성한 k8s 클러스터를 컨트롤하기 위해서는 kubernetes service에서 생성한 클러스터들을 설정파일을 다운로드 해야합니다.

위 이미지와 같이 해당 설정파일을 다운로드 한 뒤에 Server로 넣어줍시다.
간단하게 마우스 이동으로 파일을 옮기시려면 lrzsz 를 설치하여 PC와 서버 간에 간단하게 파일을 업로드, 다운로드를 하실 수 있습니다.

yum install lrzsz

설정파일이 Server에 있는데 이는 아래와 같이 사용할 수 있습니다.

kubectl –kubeconfig=/root/kubeconfig-d1f34144-76a5-46fa-a55c-7186946b8acc.yaml get nodes

원래 kubectl get nodes인데 config 파일을 이용하여 클러스터 접근 구성을 하게 되는 것입니다.
하지만 매번 명령어 입력마다 이렇게 사용할 수는 없으니 alias 설정을 해준다면 더욱 편리하게 사용할 수 있습니다.

[root@kubernetes-server-kr2 ~]# ll
total 8
-rw-r--r-- 1 root root 5538 Jun 17 02:19 kubeconfig-d1f34144-76a5-46fa-a55c-7186946b8acc.yaml


[root@kubernetes-server-kr2 ~]# kubectl --kubeconfig=/root/kubeconfig-d1f34144-76a5-46fa-a55c-7186946b8acc.yaml get nodes
NAME                  STATUS   ROLES    AGE     VERSION
nks-pool-1003-w-eoi   Ready    <none>   9m23s   v1.18.17
nks-pool-1003-w-eoj   Ready    <none>   9m22s   v1.18.17

[root@kubernetes-server-kr2 ~]# cat << EOF >> .bash_profile 
> alias kubectl='kubectl --kubeconfig="/root/kubeconfig-d1f34144-76a5-46fa-a55c-7186946b8acc.yaml"'
> EOF
[root@kubernetes-server-kr2 ~]# source .bash_profile
https://hub.docker.com/

위 이미지는 docker hub입니다.
이전에 업로드 해둔 manvscloud_dkos 파일을 배포해보겠습니다.

[root@kubernetes-server-kr2 ~]# kubectl run manvscloud --image seevirus/manvscloud_dkos:1
pod/manvscloud created
[root@kubernetes-server-kr2 ~]# kubectl get pod
NAME         READY   STATUS              RESTARTS   AGE
manvscloud   0/1     ContainerCreating   0          13s
[root@kubernetes-server-kr2 ~]# kubectl get pod
NAME         READY   STATUS         RESTARTS   AGE
manvscloud   0/1     ErrImagePull   0          22s

ErrImagePull 메시지가 발생했습니다.
왜 도커 이미지를 Pull 해오지 못한걸까요?

원인은 바로 위에서 NAT Gateway를 설정해주지 않았기때문입니다.
위에서 클러스터 생성 시 “아웃바운드 인터넷 트래픽을 활성화하기 위해서는
NAT Gateway를 반드시 생성해야한다”
라고 알려주는 메시지는 바로 NAT Gateway 설정을 해주지 않게되면 아웃바운드 인터넷 트래픽 통신이 전혀 되지 않기때문이죠.

바로 NAT Gateway를 생성해줍시다.
생성한 NAT Gateway는 Private Route Table에 연결해주어야합니다.

위 이미지와 같이 NAT Gateway를 연결해주고 다시 Server로 돌아와서 확인해보도록 합시다.

[root@kubernetes-server-kr2 ~]# kubectl get services
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   198.19.128.1   <none>        443/TCP   30m
[root@kubernetes-server-kr2 ~]# kubectl get pods -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP             NODE                  NOMINATED NODE   READINESS GATES
manvscloud   1/1     Running   0          17m   198.18.0.169   nks-pool-1003-w-eoj   <none>           <none>

ErrImagePull이었던 상태가 Running 상태로 변경되어있습니다.
정상적으로 배포가 되었군요.

[root@kubernetes-server-kr2 ~]# kubectl get all --all-namespaces
NAMESPACE     NAME                                   READY   STATUS    RESTARTS   AGE
default       pod/manvscloud                         1/1     Running   0          17m
kube-system   pod/cilium-jv5gz                       1/1     Running   0          30m
kube-system   pod/cilium-monitor-jp82w               1/1     Running   0          27m
kube-system   pod/cilium-monitor-nbvgm               1/1     Running   0          27m
kube-system   pod/cilium-operator-78f6b5db7c-77gqn   1/1     Running   0          30m
kube-system   pod/cilium-operator-78f6b5db7c-pjthh   1/1     Running   0          30m
kube-system   pod/cilium-z6gbh                       1/1     Running   0          30m
kube-system   pod/coredns-7895d49695-7cjhm           1/1     Running   0          29m
kube-system   pod/coredns-7895d49695-csj5w           1/1     Running   0          29m
kube-system   pod/csi-nks-controller-0               6/6     Running   1          28m
kube-system   pod/csi-nks-node-jtg5t                 3/3     Running   1          28m
kube-system   pod/csi-nks-node-w2cjd                 3/3     Running   1          28m
kube-system   pod/dns-autoscaler-56bf5c7f58-cz2jr    1/1     Running   0          29m
kube-system   pod/kube-proxy-6xmdd                   1/1     Running   0          30m
kube-system   pod/kube-proxy-qq27q                   1/1     Running   0          30m
kube-system   pod/ncloud-kubernetes-f5lxr            1/1     Running   0          49s
kube-system   pod/ncloud-kubernetes-kgt9p            1/1     Running   0          49s
kube-system   pod/nodelocaldns-mkzqz                 1/1     Running   0          29m
kube-system   pod/nodelocaldns-mvc7f                 1/1     Running   0          29m
kube-system   pod/snapshot-controller-0              1/1     Running   0          28m
kube-system   pod/startup-script-jtknz               1/1     Running   0          27m
kube-system   pod/startup-script-zlg28               1/1     Running   0          27m

NAMESPACE     NAME                     TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes       ClusterIP   198.19.128.1     <none>        443/TCP                  31m
kube-system   service/coredns          ClusterIP   198.19.128.3     <none>        53/UDP,53/TCP,9153/TCP   29m
kube-system   service/metrics-server   ClusterIP   198.19.128.124   <none>        443/TCP                  28m

NAMESPACE     NAME                               DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   daemonset.apps/cilium              2         2         2       2            2           <none>                   30m
kube-system   daemonset.apps/cilium-monitor      2         2         2       2            2           <none>                   27m
kube-system   daemonset.apps/csi-nks-node        2         2         2       2            2           <none>                   28m
kube-system   daemonset.apps/kube-proxy          2         2         2       2            2           kubernetes.io/os=linux   31m
kube-system   daemonset.apps/ncloud-kubernetes   2         2         2       2            2           <none>                   27m
kube-system   daemonset.apps/nodelocaldns        2         2         2       2            2           <none>                   29m
kube-system   daemonset.apps/startup-script      2         2         2       2            2           <none>                   27m

NAMESPACE     NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/cilium-operator   2/2     2            2           30m
kube-system   deployment.apps/coredns           2/2     2            2           29m
kube-system   deployment.apps/dns-autoscaler    1/1     1            1           29m

NAMESPACE     NAME                                         DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/cilium-operator-78f6b5db7c   2         2         2       30m
kube-system   replicaset.apps/coredns-7895d49695           2         2         2       29m
kube-system   replicaset.apps/dns-autoscaler-56bf5c7f58    1         1         1       29m

NAMESPACE     NAME                                   READY   AGE
kube-system   statefulset.apps/csi-nks-controller    1/1     28m
kube-system   statefulset.apps/snapshot-controller   1/1     28m

오늘은 NKS 생성과 사용법에 대해 간단하게 알아보았습니다.

NKS를 잘 사용하기 위해서는 Container Registry를 이용해서 컨테이너 이미지를 관리한다거나 Cloud Insight 서비스를 신청해서 모니터링 하기 등이 있습니다.

이는 DKOS 스터디가 진행하며 조금씩 제 블로그에 포스팅할 예정입니다.


Personal Comments

오늘은 네이버 클라우드에서 쿠버네티스 배포에 대해서만 간단하게 포스팅해보았습니다.

쿠버네티스 서비스를 사용하시기 전 VPC에 익숙하지 않으시다면 네이버 클라우드에서 교육하고 있는 Hands-on Lab을 신청하여 들어보시는 것을 권장드립니다.

네이버 클라우드는 한국어로 된 교육과 서비스로 쉽게 배우고 사용할 수 있다는 점이 큰 장점이라고 생각합니다.

추가로 요즘 회사와 주말 일정으로 포스팅되는 날짜가 일정하진 않지만 한 주에 최소 포스팅 2개를 목표로 꾸준히 작성중이니 참고 부탁드립니다.

긴 글 읽어주셔서 감사합니다.

IT/Linux/Kubernetes

YAML language 와 Kubernetes에서 요구되는 필드

안녕하세요. ManVSCloud 김수현입니다.

이번 주 일요일부터 Docker Kubernetes Online Study에서 Kubernetes 소개와 설치가 시작됩니다. 그러므로 오늘은 Yaml 파일에 대한 이해를 돕기 위해 노션에 정리해두었던 Yaml파일에 대한 내용을 정리하여 포스팅해보았습니다.


What is Yaml?

Yaml 또는 Yml 이란 사람이 쉽게 읽을 수 있는 형태로 표현된 데이터 직렬화 양식입니다.

데이터 직렬화는 메모리의 객체를 디스크에 저장하거나 통신하는 대상에게 올바른 형식으로 맞추어 전달하기 위해 바이트 스트림 형태로 만드는 것!
쉽게 말하자면 사람이 읽고 쓰기 쉽도록 만들어진 하나의 약속이라고 볼 수 있습니다.

쿠버네티스 매니페스트는 YAML과 JSON을 사용하게 되는데 주로 YAML을 이용하여 구성 파일을 작성하므로 YAML에 대해 알고 있으면 큰 도움이 됩니다.

  • 역직렬화 : 디스크에 저장된 데이터를 읽거나 네트워크를 통해 전송된 데이터를 받아 메모리에 재구축
  • 바이트 스트림 : 1 byte를 입출력 할 수 있는 스트림, JAVA에서 입출력 스트림을 통해 흘러가는 데이터의 기본 단위 (InputSteam과 OutputStream이 존재)
  • 스트림 : 데이터 처리연산을 지원하도록 소스에서 추출된 연속된 요소이며 데이터를 읽고 쓸 수 있도록 도와준다.
  • 매니페스트 : 컴퓨팅에서 집합의 일부 또는 논리정연한 단위인 파일들의 그룹을 위한 메타데이터를 포함하는 파일 (애플리케이션에 대한 필수적인 정보가 담겨있음)

Grammar

? Yaml 문법 포인트

  • Key: Value
  • mappings(해시 or 딕셔너리), sequences(배열 or 리스트), scalars(스트링 or 넘버 등)
  • 각 블록 부모-자식 관계는 들여쓰기로 구분
  • 를 이용하여 시퀀스 사용
  • # 는 주석
  • 는 문서의 시작 (스트림 시작)
  • 는 문서의 끝 (스트림 끝)
  • & 를 이용하여 anchor 설정 (정의)
  • * 를 이용하여 alias 설정 (참조)
  • 띄어쓰기

Scalars
integer: 100
string: “100” 또는 ‘100’
(“”는 이중 문자열, ”는 단일 문자열)
float: 100.0
boolean: yes

(yes/no, true/false, on/off)

→ Example
count: “1”
→ int가 아닌 string

size: ‘3.14’
→ float가 아닌 string

question: ture
→ boolean

answer: “true”
→ string

→ 추가 내용
◎ 값이 비어있으면 null (nil이 아님)
port: “80” 이라고 선언할 수 있으며 템플릿 엔진과 YAML Parser를 정상적으로 통과합니다. 하지만 쿠버네티스가 포트를 integer로 받아야할 경우 실패할 수 있습니다.
이때 YAML 노드 태그를 사용하여 특정 유형 추론을 강제화 할 수 있습니다.
port: !!int “80”
위와 같이 선언할 경우 port가 “”로 감싸져 있어도 int로 취급됩니다.
ex) age: !!str 21 (int가 아닌 string으로 강제)
◎ 추가적인 심화 내용은 아래
TIP의 YAML 기법 링크 참고


Sequences

→ Level 1

- one
- two
- three

Level 2

-
  - Lion
  - Tiger
  - Bear
-
  - Orange
  - Lemon
  - Pear

Level 3

-
  -
    - Golf
    - Soccer
    - Basketball

Mappings

Level 1

Language: English

Level 2

Language: English
  - A
  - B
  - C

Anchor & Alias

Level 1

Linux:
  - linux1: &linux1 centos
  - linux2: &linux2 ubuntu
  - linux3: &linux3 rocky
  - linux4: &linux4 suse

web_linux: *linux1
db_linux: *linux3

Level 2
(<< 를 이용하여 Override(자식 클래스에서 부모 클래스 재정의))

base: &default
  web: apache
  db: mysql
env:
  dev:
    <<: *default
    db: oracle

  prod:
    <<: *default
    web: nginx

⚠️ YAML 앵커 및 별칭은 ‘ [ ‘, ‘ ] ‘, ‘ { ‘, ‘ } ‘및 ‘ , ‘문자를 포함 할 수 없습니다.


Example

Kubernetes에서 퍼시스턴트볼륨을 생성하는 YAML 파일의 예시입니다.
(용량은 25GiB이며 ReadWriteOnce Mode로 생성)

kind: PersistentVolume
apiVersion: v1
metadata:
  name: pv0001
  labels:
    type: local
spec:
  capacity:
    storage: 25Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/data/pv01"

In-depth course

CKAD 시험까지 생각하고 있다면 k8s의 yaml 파일 작성법까지 깊게 알아보는 것도 좋지않을까 생각합니다. 생성하고자 하는 쿠버네티스 오브젝트에 대한 YAML 파일 내에 필드 값들을 설정해주게 되는데 그 필드 값에 대한 내용을 알아보도록 하겠습니다.

  • apiVersion
    : 이 오브젝트를 생성하기 위해 사용하고 있는 쿠버네티스 API 버전이 어떤 것인지

종류
v1
: 쿠버네티스에서 발행한 첫 stable release API
(대부분의 api가 포함되어 있음)
apps/v1
: 쿠버네티스의 common API 모음, Deployment, RollingUpdate, ReplicaSet을 포함
batch/v1
: 배치 프로세스, job-like task를 위한 배포 api
autoscaling/v1
: pod의 autoscale 기능을 포함하는 API, 현재는 CPU metric을 사용한 scaling만 가능
(추후에 alpha, beta version에서 memory, custom metric으로 scaling 기능 추가예정)
batch/v1beta1
: batch/v1에서 cronJob으로 job을 돌리는 api가 추가
certivicates.k8s.io/v1 beta
: 클러스터의 secure network function들이 추가된 API
(TLS 등의 기능 추가)
extensions/v1beta
: Deployments, DaemonSets, ReplicatSets, Ingress 등 상당수 feature들이 새롭게 정의된 API 그러나 상당수의 api들이 apps/v1과 같은 그룹으로 이동되어서, 쿠버네티스 1.6버젼 이후부터는 deprecated 됨
policy/v1beta1
: pod에 대한 security rule이 정의된 API
rbac.authorization.k8s.io/v1
: 쿠버네티스의 role-based access control이 가능한 function이 정의됨

  • kind
    : 어떤 종류의 오브젝트를 생성하고자 하는지 (원하는 kind에 따라 apiVersion 종류가 달라짐)

종류
Pod
: pod을 정의하여 쿠버네티스 선언(아직 배포되지 않은 상태)
ReplicationController(or ReplicaSet)
: 쿠버네티스에 선언된 pod을 배포하기 위한 선언(replicas 갯수, readiness probe 등 선언)
Service
: 동적으로 생성된 pod(각각 다른 ip)을 라벨(label)과 라벨 셀렉터(label selector)을 사용하여 하나의 서비스로 묶어주는 역할
(ex. pod에 라벨이 “wonyoung”이 선언되어 있으면, service는 “wonyoung” label이 붙은 서비스만 골라내서 그 pod간에만 로드벨런싱을 동해 서비스를 외부에 제공)

  • metadata
    : 이름, 문자열, UID, 그리고 선택적인 네임스페이스를 포함하여 오브젝트를 유일하게 구분지어줄 데이터
  • spec
    : 오브젝트에 대해 어떤 상태를 의도하는지

? 생성 가능한 오브젝트에 대한 모든 spec 확인

? Pod에 대한 spec 포맷

? Deployment에 대한 spec 포맷


TIP

? YAML 기법
? YAML 유효성 검사
? YAML to JSON
? JSON to YAML

Personal Comments

YAML을 전혀 모르던 때에 띄어쓰기 조차 문법인지 몰라서 당황했던 기억이 있습니다.
이 포스팅을 통해 많은 분들이 YAML 문법이 무엇인지 그리고 Kubernetes를 시작하기 전 많은 도움이 되길 바랍니다.

긴 글 읽어주셔서 감사합니다.

IT/Linux/Kubernetes

Docker Kubernetes Online Study 스터디 시작! (Docker의 장점과 Network)

안녕하세요. ManVSCloud 김수현입니다.

CloudNet@에서 진행하는 DOCKER KUBERNETES ONLINE STUDY가 시작되었습니다.
1주차 Docker의 기초를 시작으로 Kubernetes를 제대로 배우게 되어 흥미롭습니다.

지금까지 Docker는 Docker-compose를 이용하여 임의적으로만 사용하거나 kubernetes도 wordpress 사이트를 올려본 것이 전부라 아직 미숙했는데 이번 기회에 깊이있게 공부하고 다양한 테스트를 시작할 수 있게 되었습니다.

오늘 스터디 이전에 정리해두었던 내용 중 몇가지를 포스팅하려 합니다.
Docker의 장점과 네트워크 관련 내용입니다.


Advantages of Docker

한국어 자막 지원합니다.

위 영상은 컨테이너가 무엇인지 알려주는 영상입니다.
한국어 자막도 지원하고 설명이 잘 되어있어 1분 30초만 투자하면 컨테이너가 무엇인지 알 수 있습니다.

도커의 장점 TOP 5
  • 신속한 애플리케이션 배포 – 컨테이너에는 애플리케이션 의 최소 런타임 요구 사항이 포함되어 크기를 줄이고 신속하게 배포 할 수 있습니다.
  • 머신 간 이식성 – 애플리케이션 및 모든 종속 항목을 Linux 커널, 플랫폼 배포 또는 배포 모델의 호스트 버전과 독립적인 단일 컨테이너로 번들링 할 수 있습니다. 또한 이 컨테이너는 Docker를 실행하는 다른 머신으로 전송할 수 있으며 호환성 문제없이 실행할 수 있습니다.
  • 버전 제어 및 구성 요소 재사용 – 컨테이너의 연속 버전을 추적하고 차이점을 검사하거나 이전 버전으로 롤백 할 수 있습니다. 또 컨테이너는 이전 레이어의 구성 요소를 재사용하므로 매우 가볍습니다.
  • 공유 – 원격 저장소를 사용하여 다른 사람과 컨테이너를 공유 할 수 있습니다. 
  • 가벼운 설치 공간 및 최소한의 오버 헤드 – Docker 이미지는 일반적으로 매우 작기 때문에 신속한 제공이 가능하고 새로운 애플리케이션 컨테이너를 배포하는 시간이 단축됩니다.
  • 단순화 된 유지 관리 – Docker는 애플리케이션 종속성으로 인한 노력과 문제의 위험을 줄여줍니다.

Network

root@dkos-master:~# ip route show
default via 192.168.0.1 dev enp0s3 proto static
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
192.168.0.0/24 dev enp0s3 proto kernel scope link src 192.168.0.30

제가 docker를 처음 사용했을 때 생겼던 궁금증이었는데 이제는 많은 블로그에 포스팅된 내용이기도 합니다.
docker 설치 및 실행 후 ip route show 또는 ip a 명령어로 확인 시 docker 0의 bridge 네트워크 IP 대역이 default 설정으로 172.17.0.0/16 대역으로 설정되어 있을 것입니다.
이 ip대역 변경이 가능합니다.

/etc/docker 디렉토리 아래 daemon.json라는 .json 파일이 없는데 이걸 만들어주면 됩니다.

root@dkos-master:~# vi /etc/docker/daemon.json

예를 들어 아래와 같은 대역대로 설정해주고 저장합니다.

{
"bip": "10.3.0.1/16"
}
root@dkos-master:~# systemctl restart docker

root@dkos-master:~# ip route show
default via 192.168.0.1 dev enp0s3 proto static
10.3.0.0/16 dev docker0 proto kernel scope link src 10.3.0.1 linkdown
192.168.0.0/24 dev enp0s3 proto kernel scope link src 192.168.0.30

root@dkos-master:~# iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 10.3.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN

docker를 재시작해주면 설정해줬던 10.3.0.0/16 대역으로 변경된 것을 알 수 있습니다.

3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:2a:78:b0:a3 brd ff:ff:ff:ff:ff:ff
    inet 10.3.0.1/16 brd 10.3.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:2aff:fe78:b0a3/64 scope link
       valid_lft forever preferred_lft forever

브리지 네트워크 구성 방법에 대해 자세하게 알고싶으신 경우 아래 링크를 참고하시기 바랍니다.

또한 Docker에서는 다양한 네트워크 작동 방식이 존재합니다.
bridge, host, overlay, macvlan, none 등이 있는데 기본 네트워크 드라이브는 bridge로 설정되어 있으며 각 네트워크 작동 방식에 대해 설명하기에는 내용이 너무 방대하여 간단한 요약만 작성하겠습니다. 더 자세히 알고싶으신 경우 링크를 남겨두었으니 확인해보시기 바랍니다.

  • bridge : 동일한 Docker 호스트에서 통신하기 위해 여러 컨테이너가 필요할 때 사용
  • host : 네트워크 스택이 Docker 호스트에서 격리되어서는 안되지만 컨테이너의 다른 측면을 격리하려는 경우 사용
  • overlay : 통신을 위해 서로 다른 Docker 호스트에서 실행되는 컨테이너가 필요하거나 여러 애플리케이션이 스웜(swarm) 서비스를 사용하여 함께 작동 할 때 사용
  • macvlan : VM 설정에서 마이그레이션하거나 컨테이너가 각각 고유 한 MAC 주소를 가진 네트워크의 물리적 호스트처럼 보이도록해야 할 때 사용
  • ipvlan : ipvlan은 macvlan과 유사하지만 엔드포인트의 MAC 주소가 동일하며 L2 및 L3 모드를 지원합니다.
  • none : 모든 네트워킹을 비활성화, 스웜(swarm) 서비스 사용 불가

아래 링크는 Macvlan과 IPvlan의 차이점을 알 수 있습니다.


TIP

Docker는 단일 컨테이너 관리에 적합하도록 만들어져 있습니다.
컨테이너가 세분화되어 다수의 컨테이너화 된 앱을 사용하게 되면 관리와 오케스트레이션이 어려워집니다. 그렇다면 여기서 오케스트레이션은 무엇입니까?
오케스트라(orchestra)라는 말은 많이 들어보셨으리라 생각합니다.

오케스트레이션은 컴퓨팅, 네트워킹, 리소스 배포, 관리, 배치, 정렬을 자동화합니다.
위 컨테이너를 지휘하고 있는 이미지와 함께 보면 어떤 느낌인지 이해가 가시나요?
다수의 컨테이너가 네트워킹, 보안, 텔레메트리와 같은 서비스를 쉽게 제공하려면 이 컨테이너들을 그룹화해야 할 필요가 있습니다. 그렇기 때문에 Kubernetes, Docker Swarm, Apache Mesos, Nomad 와 같은 툴을 사용합니다.
Kubernetes는 무엇입니까? 컨테이너 오케스트레이션 툴입니다.


Personal Comments

이번 주 일요일부터는 Kubernetes에 대한 내용이 시작됩니다.
아직 화요일인데 벌써 일요일이 기다려지네요.
DKOS 스터디 진행 및 운영 해주시는 모든 운영진 분들에게 감사의 인사 올립니다.

마지막으로 컨테이너는 chroot와 namespace, cgroups과 같은 커널 기반 기술이 사용되는데 이에 대해 잘 설명이 되어있는 사이트가 있어 아래 링크로 공유합니다.

긴 글 읽어주셔서 감사합니다.