퀵랩 - Kubernetes를 통한 클라우드 조정

2021. 5. 11. 08:15IT 공부/Qwiklabs

 

※ 본 카테고리에서는 구글 클라우드 스터디잼을 통해 제공받은 퀵랩에서 자유롭게 퀘스트를 수행하며 공부한 내용을 기록하고 있습니다. 

 

google.qwiklabs.com/focuses/557?parent=catalog

실습 목표 : 간단한 쿠버네티스 demo 경험 (쿠버네티스 인프라 설정이 주요 목적이 아님!)

 

 

 

- 모놀리식(monolithic architecture)

: 하나의 서비스가 하나의 거대한 아키텍처를 갖는 것.

  하나의 비지니스 로직과 하나의 DB를 갖는다. 

  같은 어플리케이션을 하나 더 만듦으로써 고가용성 서버를 만들 수 있다. 

: 반대로는 마이크로 서비스 아키텍처(micro service architecture, MSA)가 있다. 

(참고)

lion-king.tistory.com/entry/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C-%EC%84%9C%EB%B9%84%EC%8A%A4-vs-%EB%AA%A8%EB%86%80%EB%A6%AC%EC%8B%9D-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-MicroService-vs-Monolithic-Architecture-%EA%B0%84%EB%8B%A8-%EC%86%8C%EA%B0%9C-%EB%B0%8F-%EC%A3%BC%EA%B4%80%EC%A0%81-%EC%9D%98%EA%B2%AC

 

 

- JWT (json web token)

 : 

 

(URL 인코딩, RFC3986 참고)

URL에 문자를 16진수로 나타내는 인코딩 방법

ko.wikipedia.org/wiki/%ED%8D%BC%EC%84%BC%ED%8A%B8_%EC%9D%B8%EC%BD%94%EB%94%A9

(OAuth 참고)

OAuth는 인증을 위한 프로토콜로써 ⓐ의 정보를 가져다가 ⓑ의 서비스를 이용할 수 있게끔 지원하는 API 접근 위임

d2.naver.com/helloworld/24942

(Token참고)

유저의 인증 상태를 서버나 세션에 저장하지 않는 stateless 토큰 기반 인증 시스템

velopert.com/2350

(JWT, RFC7519  참고)

필요한 모든 정보를 자체적으로 지니고 있는 json 객체를 사용하여 정보를 전달하는 토큰 인증 시스템

velopert.com/2389

 

 


 

1. cloud shell 환경에서 영역 설정

gcloud config set compute/zone us-central1-b
// Updated property [compute/zone].

 

2. 영역 설정 후 실습에 사용할 클러스터 시작

gcloud container clusters create io
// kubeconfig entry generated for io.
// NAME  LOCATION       MASTER_VERSION   MASTER_IP     MACHINE_TYPE  NODE_VERSION     NUM_NODES  STATUS
// io    us-central1-b  1.18.17-gke.100  35.193.134.2  e2-medium     1.18.17-gke.100  3          RUNNING

 

3. 깃허브 저장소 클론

gsutil cp -r gs://spls/gsp021/* .

 

4. 실습에 필요한 디렉토리로 변경 후 파일 확인

cd orchestrate-with-kubernetes/kubernetes
ls
  deployments/
  디플로이먼트 매니페스트
  
  nginx/
  nginx 구성 파일
 
  pods/
  포드 매니페스트
 
  services/
  서비스 매니페스트
 
  tls/
  TLS 인증서
 
  cleanup.sh
  정리 스크립트
 

 

5. kubectl create 명령어를 사용하여 nginx 컨테이너(k8s)의 단일 인스턴스를 실행

   → k8s가 배포를 생성함

   → pod가 작동함 (이 때, pod가 실행한느 노드에 오류가 발생해도 계속 작동함)

kubectl create deployment nginx --image=nginx:1.10.0
// deployment.apps/nginx created

 

6. 실행중인 nginx 컨테이너를 확인

kubectl get pods
// NAME                     READY   STATUS    RESTARTS   AGE
// nginx-55c6b6cb9c-t5z6b   1/1     Running   0          5m7s

 

7. kubectl expose 명령어를 사용하여 kubernetes 외부로 실행중인 nginx 컨테이너를 노출

   → k8s가 백그라운드에서 공개 IP주소가 첨부된 로드밸런서(외부 부하 분산기)를 생성함

   → 해당 IP주소를 조회하는 모든 클라이언트는 서비스 백그라운드에 있는 (이 경우에는) nginx의 포드로 라우팅됨

kubectl expose deployment nginx --port 80 --type LoadBalancer
// service/nginx exposed

 

8. 서비스 나열하기

kubectl get services
// NAME         TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
// kubernetes   ClusterIP      10.3.240.1     <none>          443/TCP        12m
// nginx        LoadBalancer   10.3.252.228   35.238.132.82   80:30012/TCP   3m33s

 

9. 원격으로 nginx 컨테이너를 조회하기 위해 외부 IP를 추가

curl http://35.238.132.82:80
/*
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
/*

 

 

10. k8s에서 kubectl을 사용하여 클러스터 만들기 및 nginx 실행, expose 완료

 

 


 

- 포드 (Pods)

 : k8s에서 1개 이상의 컨테이너가 포함된 모음

  일반적으로 상호 의존성이 높은 컨테이너가 여러 개 있으면 하나의 포드에 패키징한다. 

  네임스페이스(namespace)를 공유한다. 

  pod당 하나의 IP를 갖는다. 

  포드에는 데이터 디스크인 볼륨이 포함되어 있다.

  같은 포드 내의 컨테이너들은 통신할 수 있으며 첨부된 볼륨을 공유한다. 

  포드는 영구적으로 지속되지 않는다. (활성 여부 또는 준비 상태 검사 오류 등의 이유)

  포트가 다시 시작되면 IP 주소가 바뀔 수 있다. 

 

 


- 포드 만들기

  : 포드 구성 파일을 사용하여 만들 수 있다. 

 

1. 모놀리식(1개의 컨테이너) 포드 구성 파일 확인하기

cat pods/monolith.yaml

/*
apiVersion: v1
kind: Pod
metadata:
  name: monolith
  labels:
    app: monolith
spec:
  containers:                                   # 1개의 컨테이너로 구성된 포드 
    - name: monolith                            # 컨테이너로 몇 가지 인수가 전달됨
      image: kelseyhightower/monolith:1.0.0
      args:
        - "-http=0.0.0.0:80"
        - "-health=0.0.0.0:81"
        - "-secret=secret"
      ports:
        - name: http
          containerPort: 80                     # HTTP 트래픽용 포드 80이 개방됨
        - name: health
          containerPort: 81
      resources:
        limits:
          cpu: 0.2
          memory: "10Mi"
*/

 

2. kubectl을 사용하여 모놀리식 포드 만들기

   → 모놀리식 포드는 Docker Hub에서 모놀리식 컨테이너 이미지를 가져와서 실행하게 된다. 

kubectl create -f pods/monolith.yaml
// pod/monolith created

 

3. kubectl get pods 명령어로 기본 네임스페이스에서 실행 중인 모든 포드 나열하기

kubectl get pods
// NAME                     READY   STATUS    RESTARTS   AGE
// monolith                 1/1     Running   0          56s
// nginx-55c6b6cb9c-t5z6b   1/1     Running   0          33m

 

4. kubectl describe 명령어로 모놀리식 포드에 관한 상세 정보 출력하기

kubectl describe pods monolith
/*
Name:         monolith
Namespace:    default
Priority:     0
Node:         gke-io-default-pool-f7d25527-dk51/10.128.0.4
Start Time:   Tue, 11 May 2021 00:49:16 +0000
Labels:       app=monolith
Annotations:  <none>
Status:       Running
IP:           10.0.0.6
IPs:
  IP:  10.0.0.6
Containers:
  monolith:
    Container ID:  docker://133c96c864cc1772e72792ceaad6f36b9ea08c65a57277f198d277733ac0ecaf
    Image:         kelseyhightower/monolith:1.0.0
    Image ID:      docker-pullable://kelseyhightower/monolith@sha256:72c3f41b6b01c21d9fdd2f45a89c6e5d59b8299b52d7dd0c9491745e73db3a35
    Ports:         80/TCP, 81/TCP
    Host Ports:    0/TCP, 0/TCP
    Args:
      -http=0.0.0.0:80
      -health=0.0.0.0:81
      -secret=secret
    State:          Running
      Started:      Tue, 11 May 2021 00:49:19 +0000
    Ready:          True
    Restart Count:  0
    Limits:
      cpu:     200m
      memory:  10Mi
    Requests:
      cpu:        200m
      memory:     10Mi
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-bzvxk (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-bzvxk:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-bzvxk
    Optional:    false
QoS Class:       Guaranteed
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  3m14s  default-scheduler  Successfully assigned default/monolith to gke-io-default-pool-f7d25527-dk51
  Normal  Pulling    3m13s  kubelet            Pulling image "kelseyhightower/monolith:1.0.0"
  Normal  Pulled     3m11s  kubelet            Successfully pulled image "kelseyhightower/monolith:1.0.0"
  Normal  Created    3m11s  kubelet            Created container monolith
  Normal  Started    3m11s  kubelet            Started container monolith
*/  

 


 

- 포드와 상호작용하기

  : 포드는 기본적으로 비공개 IP 주소가 부여되어 클러스터 밖에서는 접근할 수 없다. 

   따라서, 로컬포트를 모놀리식 포드 안의 포트로 매핑하는 작업이 필요하다. 

 

1. cloud shell 상단의 open a new tab (+)을 클릭하여 두 번째 터미널을 연다. 

 

2. 두 번째 터미널에서 포드 전달을 설정

kubectl port-forward monolith 10080:80
// Forwarding from 127.0.0.1:10080 -> 80

 

3. 첫 번째 터미널에서 curl을 사용하여 pod와 통신을 시작

curl http://127.0.0.1:10080
// {"message":"Hello"}

 

4. 보안이 설정된 엔드포인트를 조회하면 인증 실패하므로, 인증 토큰을 얻기 위해 로그인

   → 로그인 성공 후 JWT 토큰 출력됨

curl -u user http://127.0.0.1:10080/login
// Enter host password for user 'user':
password
// {"token":"aaaaa.bbbbb.ccccc"}

 

5. cloud shell에서 토큰을 저장하기 위해 환경 변수 만들기

TOKEN=$(curl http://127.0.0.1:10080/login -u user|jq -r '.token')
// Enter host password for user 'user':
password
//   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
//                                  Dload  Upload   Total   Spent    Left  Speed
// 100   222  100   222    0     0    237      0 --:--:-- --:--:-- --:--:--   237

 

6. 토큰 복사 후 토큰으로 curl을 사용하여 보안이 설정된 엔드포인트 조회하기

curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:10080/secure
// {"message":"Hello"}

 

7. kubectl logs 명령어로 monolith 포드의 로그를 확인할 수 있다. 

kubectl logs monolith
/*
2021/05/11 00:49:19 Starting server...
2021/05/11 00:49:19 Health service listening on 0.0.0.0:81
2021/05/11 00:49:19 HTTP service listening on 0.0.0.0:80
127.0.0.1:37604 - - [Tue, 11 May 2021 00:57:31 UTC] "GET / HTTP/1.1" curl/7.64.0
127.0.0.1:37702 - - [Tue, 11 May 2021 00:59:48 UTC] "GET /secure HTTP/1.1" curl/7.64.0
127.0.0.1:37746 - - [Tue, 11 May 2021 01:00:58 UTC] "GET /login HTTP/1.1" curl/7.64.0
127.0.0.1:37880 - - [Tue, 11 May 2021 01:03:52 UTC] "GET /login HTTP/1.1" curl/7.64.0
127.0.0.1:37942 - - [Tue, 11 May 2021 01:05:19 UTC] "GET /secure HTTP/1.1" curl/7.64.0
*/

 

8. 세 번째 터미널을 열고 -f 플래스를 사용하여 실시간 로그 스트림을 가져오기

kubectl logs -f monolith
/*
2021/05/11 00:49:19 Starting server...
2021/05/11 00:49:19 Health service listening on 0.0.0.0:81
2021/05/11 00:49:19 HTTP service listening on 0.0.0.0:80
127.0.0.1:37604 - - [Tue, 11 May 2021 00:57:31 UTC] "GET / HTTP/1.1" curl/7.64.0
127.0.0.1:37702 - - [Tue, 11 May 2021 00:59:48 UTC] "GET /secure HTTP/1.1" curl/7.64.0
127.0.0.1:37746 - - [Tue, 11 May 2021 01:00:58 UTC] "GET /login HTTP/1.1" curl/7.64.0
127.0.0.1:37880 - - [Tue, 11 May 2021 01:03:52 UTC] "GET /login HTTP/1.1" curl/7.64.0
127.0.0.1:37942 - - [Tue, 11 May 2021 01:05:19 UTC] "GET /secure HTTP/1.1" curl/7.64.0
*/

 

9. 첫 번째 터미널에서 curl을 사용하면 세 번째 터미널에서 로그가 실시간 업데이트 된다. 

curl http://127.0.0.1:10080

 

 

10. kubectl exec 명령어로 모놀리식 포드의 대화형 셸 실행하기 

    → 컨테이너 내부에서 문제를 해결할 때 필요

kubectl exec monolith --stdin --tty -c monolith /bin/sh
/*
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ #
*/

 

11. 셸에서 ping 명령어로 외부 연결을 테스트하기

ping -c 3 google.com
/*
PING google.com (108.177.120.139): 56 data bytes
64 bytes from 108.177.120.139: seq=0 ttl=114 time=1.332 ms
64 bytes from 108.177.120.139: seq=1 ttl=114 time=1.316 ms
64 bytes from 108.177.120.139: seq=2 ttl=114 time=1.041 ms

--- google.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 1.041/1.229/1.332 ms
*/

 

12. 대화형 셸은 사용 후 반드시 로그아웃 한다. 

exit

 


- 서비스

  : 포드를 위해 안정적인 엔드포인트를 제공한다. 

    라벨을 사용하여 어떤 포드에서 작동할지 결정한다. 

    포드에 라벨이 정확히 지정되어 있다면 서비스가 자동으로 감지하고 노출시킨다. 

    서비스 유형에 따라 3가지 유형의 액세스 수준이 제공된다.

  ClusterIP (내부)   기본 유형
  클러스터 안에서만 볼 수 있다. 
  NodePort   클러스터의 각 노드에 외부에서 액세스 가능한 IP 주소를 제공
  LoadBalancer   클라우드 제공업체로부터 부하 분산기를 추가하며,
  서비스에서 유입되는 트래픽을 내부에 있는 노드로 전달

 

 

 


- 서비스 만들기

 

1. k8s가 있는 디렉토리로 이동

cd ~/orchestrate-with-kubernetes/kubernetes

 

2. 모놀리식 서비스 구성파일 조회

cat pods/secure-monolith.yaml

 

3. 보안이 설정된 모놀리식 포드와 구성 데이터 만들기

kubectl create secret generic tls-certs --from-file tls/
// secret/tls-certs created
kubectl create configmap nginx-proxy-conf --from-file nginx/proxy.conf
// configmap/nginx-proxy-conf created
kubectl create -f pods/secure-monolith.yaml
// pod/secure-monolith created

 

4. 모놀리식 서비스 구성 파일 확인

cat services/monolith.yaml
/*
kind: Service
apiVersion: v1
metadata:
  name: "monolith"
spec:
  selector:                  # app: monoloth 및 secure: enabled 라벨이 지정된 포드를
    app: "monolith"          # 자동으로 찾고 노출시키는 선택기가 있음
    secure: "enabled"
  ports:                     # 외부 트래픽을 포트 31000에서 포트 443의 nginx로 전달하기 위해
    - protocol: "TCP"        # NodePort를 노출시켜야 함
      port: 443
      targetPort: 443
      nodePort: 31000
  type: NodePort
*/  

 

5. kubectl create 명령어로 모놀리식 서비스 구성 파일에서 모놀리식 서비스를 만들기

kubectl create -f services/monolith.yaml
// service/monolith created

 

6. gcloud compute firewall-rules 명령어로 NodePort(노출됨)의 모놀리식 서비스로 TCP 트래픽을 보내는 방화벽 규칙을 만든다. 

gcloud compute firewall-rules create allow-monolith-nodeport --allow=tcp:31000
/*
Creating firewall...⠹Created [https://www.googleapis.com/compute/v1/projects/qwiklabs-gcp-01-16237cdae72a/global/firewalls/allow-monolith-nodeport].
Creating firewall...done.
NAME                     NETWORK  DIRECTION  PRIORITY  ALLOW      DENY  DISABLED
allow-monolith-nodeport  default  INGRESS    1000      tcp:31000        False
*/

 


- 포트 전달 없이 클러스터 밖에서 안전한 모놀리식 서비스 조회하기

 

1. 노드 1개의 외부 IP 주소 가져오기

gcloud compute instances list
/*
NAME                               ZONE           MACHINE_TYPE  PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP     STATUS
gke-io-default-pool-fdb086cf-g9bv  us-central1-b  e2-medium                  10.128.0.2   104.197.2.126   RUNNING
gke-io-default-pool-fdb086cf-pmz9  us-central1-b  e2-medium                  10.128.0.3   34.68.217.152   RUNNING
gke-io-default-pool-fdb086cf-sgqx  us-central1-b  e2-medium                  10.128.0.4   35.238.135.160  RUNNING
*/

 

1. 현재 모놀리식 서비스에 엔드포인트가 없으므로 kubectl get pods 명령어로 모놀리식 라벨이 지정되어 실행되는 포드를 확인한다. 

kubectl get pods -l "app=monolith"
/*
NAME              READY   STATUS    RESTARTS   AGE
monolith          1/1     Running   0          27m
secure-monolith   2/2     Running   0          20m
*/

 

2. kubectl labe 명령어로 보안이 설정된 모놀리식 포드에서 누락된 secure=enabled 라벨을 추가하고 업데이트 내역을 확인한다. 

kubectl label pods secure-monolith 'secure=enabled'
// pod/secure-monolith labeled
kubectl get pods secure-monolith --show-labels
// NAME              READY   STATUS    RESTARTS   AGE   LABELS
// secure-monolith   2/2     Running   0          23m   app=monolith,secure=enabled

 

3. 모놀리식 서비스의 엔드포인트 목록을 확인한다. 

kubectl describe services monolith | grep Endpoints
// Endpoints:                10.0.1.5:443

 

4. 노드 중 하나를 조회하여 엔트포인트 테스트 하기

gcloud compute instances list
/*
NAME                               ZONE           MACHINE_TYPE  PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP     STATUS
gke-io-default-pool-fdb086cf-g9bv  us-central1-b  e2-medium                  10.128.0.2   104.197.2.126   RUNNING
gke-io-default-pool-fdb086cf-pmz9  us-central1-b  e2-medium                  10.128.0.3   34.68.217.152   RUNNING
gke-io-default-pool-fdb086cf-sgqx  us-central1-b  e2-medium                  10.128.0.4   35.238.135.160  RUNNING
*/
curl -k https://35.238.135.160:31000
// {"message":"Hello"}

 


- k8s로 애플리케이션 배포하기

 

- 디플로이먼트 (deployments)

  : 실행 중인 포드의 개수가 사용자가 명시한 포드 개수와 동일하게 만드는 선언적 방식

    디플로이먼트는 pod 관리에서 낮은 수준의 세부정보를 추상화하는 것이 주요 이점

    디플로이먼트는 백그라운드에서 복제본 집합을 사용하여 pod의 시작 및 중지를 관리

    Pods를 업데이트하거나 확장해야 할 경우 배포에서 처리

    포드가 중지되면 디플로이먼트에서 재시작을 담당하여 처리

 

 

 

 

 


- 디플로이먼트 만들기

 

1. 디플로이먼트 실습에서 사용할 모놀리식 앱의 서비스 구성

  auth   인증된 사용자를 위한 JWT 토큰을 생성
  hello   인증된 사용자를 안내
  frontend   트래픽을 auth 및 hello 서비스로 전달

 

2. auth 디플로이먼트 구성 파일 검토

cat deployments/auth.yaml
/*
apiVersion: apps/v1
kind: Deployment
metadata:
  name: auth
spec:
  selector:
    matchLabels:
      app: auth
  replicas: 1
  template:
    metadata:
      labels:
        app: auth
        track: stable
    spec:
      containers:
        - name: auth
          image: "kelseyhightower/auth:2.0.0"
          ports:
            - name: http
              containerPort: 80
            - name: health
              containerPort: 81
          resources:
            limits:
              cpu: 0.2
              memory: "10Mi"
          livenessProbe:
            httpGet:
              path: /healthz
              port: 81
              scheme: HTTP
            initialDelaySeconds: 5
            periodSeconds: 15
            timeoutSeconds: 5
          readinessProbe:
            httpGet:
              path: /readiness
              port: 81
              scheme: HTTP
            initialDelaySeconds: 5
            timeoutSeconds: 1
*/            

 

3. kubectl create 명령어로 auth 디플로이먼트 개체를 만든다. 

   → 디플로이먼트 매니페스트 데이터를 준수하는 포드가 만들어짐

kubectl create -f deployments/auth.yaml
// deployment.apps/auth created

 

4. kybectl create 명령어로 auth 디플로이먼트용 서비스를 만든다. 

kubectl create -f services/auth.yaml
// service/auth created

 

5. hello 디플로이먼트의 개체와 서비스를 만든다. 

kubectl create -f deployments/hello.yaml
// deployment.apps/hello created
kubectl create -f services/hello.yaml
// service/hello created

 

6. frontend 디플로이먼트의 개체를 만들고 노출한다. 

   → frontend를 만들기 위해 컨테이너에 구성 데이터를 보관해야 하므로 추가 단계가 필요하다. 

kubectl create configmap nginx-fontend-conf --from-file=nginx/frontend.conf   // 추가단계
// configmap/nginx-fontend-conf created
kubectl create -f deployments/frontend.yaml
// deployment.apps/frontend created
kubectl create -f services/frontend.yaml
// service/frontend created

 

7. 외부 IP 주소 확인 후 curl 명령어로 frontend와 상호작용해본다. 

kubectl get services frontend
/*
NAME       TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)         AGE
frontend   LoadBalancer   10.3.244.228   34.121.75.169   443:30724/TCP   112s
*/

 


 

 

반응형