kubernetes 실습

이상민·2023년 7월 1일
0

kubernetes

목록 보기
2/2

클러스터 변경

여러개의 클러스터를 동시에 사용하는 경우 클러스터를 변경해서 배포해야 함.

클러스터 이름 확인

$ kubectl config view

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://35.226.187.168
  name: gke_continual-tine-390202_us-central1-c_development
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://35.238.86.227
  name: gke_continual-tine-390202_us-central1-c_production
...

클러스터 이름 변경

클러스터 이름은 gke_continual-tine...<namespace_name> 형태로 매우 길다.
이때 클러스터 이름을 $ vi ~/.kube/config 명령을 통해 변경 가능하다.

클러스터 컨텍스트 전환

$ kubectl config use-context <cluster_name>

$ kubectl config use-context gke_continual-tine-390202_us-central1-c_production

Switched to context "gke_continual-tine-390202_us-central1-c_production".

현재 클러스터 확인

$ kubectl config current-context

gke_continual-tine-390202_us-central1-c_production

멀티 클러스터를 운영하는 환경에서는 내가 실행하는 명령이 어떤 클러스터로 전송되는지 확인!

namespace 생성

$ kubectl create nampespace <namespace_name>

$ kubectl get namespace 를 통해 현재 cluster의 namespace 확인이 가능하다.

각 클러스터별 namespace

각 클러스터 development, production 에는 order, payment, delivery namespace가 존재함.

Service 생성

main Service 구성

$ vi service/02_service-nodeport.yaml

apiVersion: v1
kind: Service
metadata:
  name: order-app
  namespace: order
spec:
  type: NodePort
  selector:
    app: order
    version: "1.0"
  ports:
  - port: 80
    targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: payment-app
  namespace: payment
spec:
  type: NodePort
  selector:
    app: payment
    version: "1.0"
  ports:
  - port: 80
    targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: delivery-app
  namespace: delivery
spec:
  type: NodePort
  selector:
    app: delivery
    version: "1.0"
  ports:
  - port: 80
    targetPort: 8080

각 namespace별로 Service를 작성하고 다른 namespace의 pod끼리 통신하기 위해 type은 NodePort로 설정하였다.

$ kubectl apply -f service/02_service-nodeport.yaml

서비스 배포.

통신용 Service 배포

$ vi service/02_communicate-another-namespace-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: payment
  namespace: order
spec:
  type: ExternalName
  externalName: payment-app.payment.svc.cluster.local # 외부 목적지로 가기 위한 service
  ports:
  - port: 80
---
apiVersion: v1
kind: Service
metadata:
  name: delivery
  namespace: order
spec:
  type: ExternalName
  externalName: delivery-app.delivery.svc.cluster.local
  ports:
  - port: 80

order namespace에서 payment, delivery namespace에 접근하는 용도의 Service를 배포.
Type은 ExternalName , exteralName은 <service_name>.<namespace_name>.svc.cluster.local 로 지정.
order namespace의 payment service가 service namespace로 서비스 호출.

ConfigMap 생성

$kubectl create configmap port-config -n order --from-file=configs/ORDER_HTTP_PORT 
$kubectl create configmap port-config -n payment --from-file=configs/PAYMENT_HTTP_PORT 
$kubectl create configmap port-config -n delivery --from-file=configs/DELIVERY_HTTP_PORT 

..._HTTP_PORT file은 8080 값만 저장되어 있으며 8080포트를 지정하는 ConfigMap을 각 namespace별로 생성함.

pod를 deployment로 배포

$ kubectl apply -f <directory/yaml_file>

$ vi deployment/03_deployment-order.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-1.0
  namespace: order
spec:
  selector:
    matchLabels:
      app: order
      version: "1.0"
  template:
    metadata:
      labels:
        app: order
        version: "1.0"
    spec:
      containers:
      - name: order
        image: yoonjeong/snackbar-order:1.0
        resources:
          limits:
            memory: "64Mi"
            cpu: "50m"
        ports:
        - containerPort: 8080
        env:
          - name: PORT
            valueFrom:
              configMapKeyRef:
                key: ORDER_HTTP_PORT
                name: port-config # 저장한 configmap name

ConfigMap으로 지정한 ORDER_HTTP_PORT 를 PORT라는 환경 변수로 container에 전달.
payment, delivery도 내용은 동일.

$ kubectl apply -f deployment/03_deployment-order.yaml

deployment를 배포하고

$ kubectl get pod -n order -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP           NODE                                        NOMINATED NODE   READINESS GATES
order-1.0-bb47dbf9-8q2nq   1/1     Running   0          61s   10.100.0.5   gke-production-default-pool-c4f7f203-x7hg   <none>           <none>

$ kubectl get endpoints order-app -n order
NAME        ENDPOINTS         AGE
order-app   10.100.0.5:8080   130m

endpoint가 할당됨.

Port-Forward

$ kubectl port-forward <pod_name> <local_port>:<container_port>
혹은
$ kubectl port-forward service/<service_name> <local_port>:<container_port>
포트 포워드는 요청을 통해 해당 서비스가 제대로 동작하는지 확인할 때 사용.

$ kubectl port-forward service/order-app 8080:80 -n order
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Handling connection for 8080

$ curl localhost:8080
Welcome to Snackbar!
Order what you want!

===== Host Info =====
HostIP: 10.100.0.5
HostName: order-1.0-bb47dbf9-8q2nq

제대로 동작한다면 기존에 설정한 값이 리턴될 것.

pod에서 다른 namespace의 pod의 응답 확인

FQND

$ kubectl exec <pod_name> -- curl -sv <service_name>.<namespace_name>.svc.cluster.local
FQND(fully qualified domain name)을 통해 다른 namespace로 접근 가능.

$ kubectl exec delivery-1.0-78596677ff-xt6hm -n delivery -- curl -sv order-app.order.svc.cluster.local
*   Trying 10.104.15.145:80...
* Connected to order-app.order.svc.cluster.local (10.104.15.145) port 80 (#0)
> GET / HTTP/1.1
> Host: order-app.order.svc.cluster.local
> User-Agent: curl/7.79.1
> Welcome to Snackbar!
Order what you want!

===== Host Info =====
HostIP: 10.100.0.5
HostName: order-1.0-bb47dbf9-8q2nqAccept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Date: Sun, 02 Jul 2023 07:16:06 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< Content-Length: 118
<
{ [118 bytes data]
* Connection #0 to host order-app.order.svc.cluster.local left intact

ExternalName

$ kubectl exec <pod_name> -n <namespace_name> \
-- curl -sv <service_name>.<namespace_name>.svc.cluster.local

FQDN과의 차이점이라면 FQDN은 현재 pod -> <요청을 보내고자 하는 service_name>.<요청을 보내고자 하는 namespace_name>이라면 ExternalName을 사용하는 경우
현재 pod -> <현재 pod의 service_name>.<현재 namespace_name>이다.

apiVersion: v1
kind: Service
metadata:
  name: delivery
  namespace: order
spec:
  type: ExternalName
  externalName: delivery-app.delivery.svc.cluster.local
  ports:
  - port: 80

위는 order -> payment로 요청을 보내기 위한 Service의 설정 일부분이다.

$ kubectl get svc -n order
NAME        TYPE           CLUSTER-IP      EXTERNAL-IP                               PORT(S)        AGE
delivery    ExternalName   <none>          delivery-app.delivery.svc.cluster.local   80/TCP         169m
order-app   NodePort       10.104.15.145   <none>                                    80:32666/TCP   177m
payment     ExternalName   <none>          payment-app.payment.svc.cluster.local     80/TCP         169m
$ kubectl exec order-1.0-bb47dbf9-8q2nq -n order -- curl -sv delivery.order.svc.cluster.local
*   Trying 10.104.3.6:80...
* Connected to delivery.order.svc.cluster.local (10.104.3.6) port 80 (#0)
> GET / HTTP/1.1
> Host: delivery.order.svc.cluster.local
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Date: Sun, 02 Jul 2023 07:29:40 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< Content-Length: 119
<
{ [119 bytes data]
* Connection #0 to host delivery.order.svc.cluster.local left intact
Welcome to Snackbar!
Check Delievery!

===== Host Info =====
HostIP: 10.100.1.9
HostName: delivery-1.0-78596677ff-xt6hm

order namespace의 delivery 서비스를 사용해 동일 namespace의 pod, service를 통해 다른 namespace로 요청을 보낼 수 있다.

Ingress

curl -H "Host: <host_path>" --request GET $INGRESS_IP/<endpoint>
Ingress를 통해 외부 IP로부터 접근이 가능해진다.
export INGRESS_IP=$(kubectl get ingress <ingress_name> -n <namespace_name> -o jsonpath="{.status.loadBalancer.ingress[0].ip}")
위의 방식으로 INGRESS_IP를 환경 변수로 설정 가능하다.

$ vi ingress/ingress-snackbar.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: snackbar
  namespace: order
spec:
  rules:
  - host: order.fast-snackbar.com
    http:
      paths:
      - pathType: Prefix
        path: /
        backend: 
          service:
            name: order-app
            port:
              number: 80
$ kubectl apply -f ingress/ingress-snackbar.yaml
ingress.networking.k8s.io/snackbar created

$ kubectl get ingress snackbar -n order
NAME       CLASS    HOSTS                     ADDRESS          PORTS   AGE
snackbar   <none>   order.fast-snackbar.com   34.160.230.242   80      21m

order.fast-snackbar.com 를 사용하여 외부로부터 접근.

$ curl -H "Host: order.fast-snackbar.com" --request GET $INGRESS_IP/menus
We have 4 snacks!
1. Pizza: 10,000
2. Burger: 5,000
3. Coke: 1,000
4. Juice: 1000

===== Host Info =====
HostIP: 10.100.0.5
HostName: order-1.0-bb47dbf9-8q2nq

INGRESS_IP를 통해 접근하면 order namespace의 service인 order-app 에 접근하고 order namespace의 pod인 order-1.0-bb47dbf9-8q2nq 가 응답하는 것을 확인할 수 있다.
이때 order namespace의 pod인 order-1.0-bb47dbf9-8q2nqpayment namespace에 요청한 결과를 얻어 사용자에게 제공한다.

블루그린 배포

새로운 버전이 준비된 상태에서 한번에 트래픽을 전환하여 새로운 pod로 요청이 가도록 하는 방식. 그린 pod(new pod)를 먼저 준비하고 service object의 목적지를 그린 pod로 변경한다. selector를 변경하게 되면 서비스의 요청이 새로운 pod로 전달된다.
블루 pod(old pod)로는 요청이 전달되지 않으므로 롤백용으로 남기거나 삭제한다.
selector를 이용해 트래픽을 바꾸는 것

$ vi deployment/05_deployment-order.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-2.0
  namespace: order
spec:
  selector:
    matchLabels:
      app: order
      version: "2.0"
  template:
    metadata:
      labels:
        app: order
        version: "2.0"
    spec:
      containers:
      - name: order
        image: yoonjeong/snackbar-order:2.0
        resources:
          limits:
            memory: "64Mi"
            cpu: "50m"
        ports:
        - containerPort: 8080
        env:
          - name: PORT
            valueFrom:
              configMapKeyRef:
                key: ORDER_HTTP_PORT
                name: port-config

기존의 03_deployment-order.yaml 에서 버전만 1.0 -> 2.0으로 변경함.

$ kubectl apply -f deployment/05_deployment-order.yaml
deployment.apps/order-2.0 created

새로운 버전을 배포하면

$ kubectl get pod -n order
NAME                         READY   STATUS    RESTARTS   AGE
order-1.0-bb47dbf9-8q2nq     1/1     Running   0          5h4m
order-2.0-6c4c75d65c-jzknb   1/1     Running   0          68s

$ kubectl get deployment -n order
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
order-1.0   1/1     1            1           5h3m
order-2.0   1/1     1            1           21s

기존의 1.0 버전과 2.0 버전이 공존한다.

2.0으로 전환

$ vi service/05_service-blue-green.yaml

apiVersion: v1
kind: Service
metadata:
  name: order-app
  namespace: order
spec:
  type: NodePort
  selector:
    app: order
    version: "2.0"
  ports:
  - port: 80
    targetPort: 8080

기존 02_service-nodeport.yaml 와 달리 selector 에서 version이 1.0 -> 2.0으로 바뀜.

$ kubectl apply -f service/05_service-blue-green.yaml
service/order-app configured

배포 후

$ kubectl get svc -n order -o wide
NAME        TYPE           CLUSTER-IP      EXTERNAL-IP                               PORT(S)        AGE     SELECTOR
delivery    ExternalName   <none>          delivery-app.delivery.svc.cluster.local   80/TCP         7h15m   <none>
order-app   NodePort       10.104.15.145   <none>                                    80:32666/TCP   7h23m   app=order,version=2.0
payment     ExternalName   <none>          payment-app.payment.svc.cluster.local     80/TCP         7h15m   <none>

$ curl -sv -H "Host: order.fast-snackbar.com" --request GET $INGRESS_IP
*   Trying 34.160.230.242:80...
* Connected to 34.160.230.242 (34.160.230.242) port 80 (#0)
> GET / HTTP/1.1
> Host: order.fast-snackbar.com
> User-Agent: curl/7.85.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Date: Sun, 02 Jul 2023 11:54:24 GMT
< Content-Length: 115
< Via: 1.1 google
<
New Order 2.0!!
Order what you want!

===== Host Info =====
HostIP: 10.100.0.7
HostName: order-2.0-6c4c75d65c-jzknb* Connection #0 to host 34.160.230.242 left intact

버전이 2.0으로 바뀐것을 확인.

카나리 배포

블루그린과 달리 selector 를 변경하지 않고 n개의 pod를 연결하여 pod 개수를 유지시키며 다른 버전의 pod를 비교하여 test를 진행함.

$ vi service/06_service-canary.yaml
apiVersion: v1
kind: Service
metadata:
  name: order-app
  namespace: order
spec:
  type: NodePort
  selector:
    app: order
  ports:
  - port: 80
    targetPort: 8080

selector에 버전 정보가 존재하지 않음.

$ kubectl apply -f service/06_service-canary.yaml
service/order-app configured

$ kubectl get svc -n order -o wide
NAME        TYPE           CLUSTER-IP      EXTERNAL-IP                               PORT(S)        AGE     SELECTOR
delivery    ExternalName   <none>          delivery-app.delivery.svc.cluster.local   80/TCP         7h35m   <none>
order-app   NodePort       10.104.15.145   <none>                                    80:32666/TCP   7h44m   app=order
payment     ExternalName   <none>          payment-app.payment.svc.cluster.local     80/TCP         7h35m   <none>

각 버전별 pod 배포

$ kubectl scale deployment order-1.0 -n order --replicas=10
$ kubectl scale deployment order-2.0 -n order --replicas=0

--replicas 를 사용하여 해당 버전의 원하는 만큼 pod를 배포한다.

$ kubectl scale deployment order-2.0 -n order --replicas=2
$ kubectl scale deployment order-1.0 -n order --replicas=8

2.0 버전의 pod를 2개로 늘리고 1.0 버전의 pod를 8개로 감소시킴.

결과 확인

$ for i in {1..10};
> do curl -sv -H "Host: order.fast-snackbar.com" --request GET $INGRESS_IP
> done
*   Trying 34.160.230.242:80...
* Connected to 34.160.230.242 (34.160.230.242) port 80 (#0)
> GET / HTTP/1.1
> Host: order.fast-snackbar.com
> User-Agent: curl/7.85.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Date: Sun, 02 Jul 2023 12:19:29 GMT
< Content-Length: 119
< Via: 1.1 google
<
Welcome to Snackbar!
Order what you want!

===== Host Info =====
HostIP: 10.100.1.11
HostName: order-1.0-bb47dbf9-qnnv5* Connection #0 to host 34.160.230.242 left intact
*   Trying 34.160.230.242:80...
* Connected to 34.160.230.242 (34.160.230.242) port 80 (#0)
> GET / HTTP/1.1
> Host: order.fast-snackbar.com
> User-Agent: curl/7.85.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Date: Sun, 02 Jul 2023 12:19:30 GMT
< Content-Length: 116
< Via: 1.1 google
<
New Order 2.0!!
Order what you want!

===== Host Info =====
HostIP: 10.100.0.12
HostName: order-2.0-6c4c75d65c-dhdkk* Connection #0 to host 34.160.230.242 left intact
*   Trying 34.160.230.242:80...
* Connected to 34.160.230.242 (34.160.230.242) port 80 (#0)

새로운 버전의 pod을 배포한 후에 트래픽의 반응을 확인.
블루그린의 경우 새 버전을 배포하였을 때 오류가 발생한다면 치명적임.
일부 pod에서 문제가 없다면 전체 pod로 배포.
리스크를 줄일 수 있음.

삭제

$ kubectl delete ingress snackbar -n order
$ kubectl delete service order -n order
$ kubectl delete service payment -n order
$ kubectl delete service delivery -n order
$ kubectl delete deployment order -n order 
$ kubectl delete deployment payment -n payment 
$ kubectl delete deployment delivery -n delivery 

0개의 댓글