도커/쿠버네티스를 활용한 컨테이너 개발 실전 입문 - 06. 쿠버네티스 클러스터 구축

백근영·2020년 1월 28일
0
post-thumbnail

03. GKE에 mysql 구축

퍼시스턴트볼륨과 퍼시스턴트볼륨클레임

퍼시스턴트 데이터를 다루는 컨테이너를 도커로 실행할 때는 데이터 볼륨을 이용했다.
표준 데이터 볼륨은 결국 호스트 머신에 위치하기 때문에, 이러한 방식은 컨테이너의 호스트에 대한
의존성을 강화하는 부작용을 낳는다.

쿠버네티스의 경우 호스트에서 분리할 수 있는 외부 스토리지를 볼륨으로 사용하므로써 이러한 문제를 해결한다.
퍼시스턴트볼륨 혹은 퍼시스턴트볼륨클레임은 이 외부 스토리지의 확보를 위한 쿠버네티스 리소스이다.
퍼시스턴트볼륨은 스토리지 그 자체라고 볼 수 있으며, 반면 볼륨클레임은 추상화된 논리 리소스로, 퍼시스턴트볼륨과는 달리
용량을 필요한 만큼 동적으로 확보할 수 있다.

스토리지클래스

스토리지클래스는 퍼시스턴트볼륨으로 확보하는 스토리지의 종류를 정의하는 리소스이다.
퍼시스턴트볼륨을 정의하는 매니페스트 파일에서는 스토리지클래스를 지정하는 storageClassName이라는 필드가 존재한다.
실습에서 사용할 스토리지클래스를 위한 매니페스트 파일을 작성하고, 클러스터에 반영한다.

storage-class-ssd.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
    name: ssd
    annotations:
        storageclass.kubernetes.io/is-default-class: "false"
    labels:
        kubernetes.io/cluster-service: "true"
provisioner: kubernetes.io/gce-pd
parameters:
    type: pd-ssd

parameters.type 필드에서 해당 스토리지클래스가 '표준' 타입인지 'SSD' 타입인지 설정할 수 있다.

스테이트풀세트(statefulSet)

디플로이먼트는 퍼시스턴트 데이터를 갖지 않는 stateless한 애플리케이션을 배포하는데 적절하다.
반면 stateful한 애플리케이션을 배포하는 데에는 statefulSet라는 리소스를 사용한다.
이 statefulset를 이용해서 배포할 mysql-master 서비스의 매니페스트 파일은 다음과 같다.
mysql-master.yaml

apiVersion: v1
kind: Service
metadata:
  name: mysql-master
  labels:
    app: mysql-master
spec:
  ports:
  - port: 3306
    name: mysql
  clusterIP: None
  selector:
    app: mysql-master
    
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql-master
  labels:
    app: mysql-master
spec:
  serviceName: "mysql-master"
  selector:
    matchLabels:
      app: mysql-master
  replicas: 1
  template:
    metadata:
      labels:
        app: mysql-master
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: mysql
        image: gihyodocker/tododb:latest
        imagePullPolicy: Always
        args:
        - "--ignore-db-dir=lost+found"
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "gihyo"
        - name: MYSQL_DATABASE
          value: "tododb"
        - name: MYSQL_USER
          value: "gihyo"
        - name: MYSQL_PASSWORD
          value: "gihyo"
        - name: MYSQL_MASTER
          value: "true"
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
  volumeClaimTemplates:
  - metadata:
      name: mysql-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: ssd
      resources:
        requests:
          storage: 4Gi

volumeClaimTemplates 필드를 정의해서 퍼시스턴트볼륨클레임을 파드마다 자동으로 생성하도록 할 수 있다.
이 덕분에 파드가 요구하는 퍼시스턴트볼륨클레임을 매번 만들지 않아도 된다.

04. GKE에 TODO API 구축

api 서버를 구축하기 위한 매니페스트 파일을 다음과 같이 작성한다.
결합성이 높은 nginx와 API 서버를 하나의 파드로 묶어 배포한다.

todo-api.yaml

apiVersion: v1
kind: Service
metadata:
  name: todoapi
  labels:
    app: todoapi
spec:
  selector:
    app: todoapi
  ports:
    - name: http
      port: 80
      
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: todoapi
  labels:
    name: todoapi
spec:
  replicas: 2
  selector:
    matchLabels:
      app: todoapi
  template:
    metadata:
      labels:
        app: todoapi
    spec:
      containers:
      - name: nginx
        image: gihyodocker/nginx:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 80
        env:
        - name: WORKER_PROCESSES
          value: "2"
        - name: WORKER_CONNECTIONS
          value: "1024"
        - name: LOG_STDOUT
          value: "true"
        - name: BACKEND_HOST
          value: "localhost:8080"
      - name: api
        image: gihyodocker/todoapi:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
        env:
        - name: TODO_BIND
          value: ":8080"
        - name: TODO_MASTER_URL
          value: "gihyo:gihyo@tcp(mysql-master:3306)/tododb?parseTime=true"
        - name: TODO_SLAVE_URL
          value: "gihyo:gihyo@tcp(mysql-slave:3306)/tododb?parseTime=true"

nginx의 경우 api 서버의 호스트를 환경변수로 전달해야 하는데, 같은 파드 안에 api 서버가 존재하므로
localhost로 변수값을 전달해주면 된다.

api의 경우 db 연결을 위한 connection string이 필요하다. 마스터와 슬레이브 각각은 mysql-master, mysql-slave로
네임 레졸루션 되어있기 때문에 이 값을 이용해 connection string을 만들어 환경변수로 전달한다.

$ kubectl get pod -l app=todoapi
NAME                      READY   STATUS    RESTARTS   AGE
mysql-slave-0             1/1     Running   0          80m
mysql-slave-1             1/1     Running   0          80m
todoapi-cdffbff68-nfbtx   2/2     Running   0          69m
todoapi-cdffbff68-q6xzk   2/2     Running   0          69m

api의 경우 statefulset로 배포한 mysql과는 다르게 파드 이름 뒤에 무작위로 suffix가 붙는 것을 확인할 수 있다.

05. GKE에 TODO 웹 애플리케이션 구축

todo-web.yaml

apiVersion: v1
kind: Service
metadata:
  name: todoweb
  labels:
    app: todoweb
spec:
  selector:
    app: todoweb
  ports:
    - name: http
      port: 80
  type: NodePort
  
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: todoweb
  labels:
    name: todoweb
spec:
  replicas: 2
  selector:
    matchLabels:
      app: todoweb
  template:
    metadata:
      labels:
        app: todoweb
    spec:
      volumes: # 1
      - name: assets
        emptyDir: {}
      containers:
      - name: nginx
        image: gihyodocker/nginx-nuxt:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 80
        env:
        - name: WORKER_PROCESSES
          value: "2"
        - name: WORKER_CONNECTIONS
          value: "1024"
        - name: LOG_STDOUT
          value: "true"
        - name: BACKEND_HOST
          value: "localhost:3000"
        volumeMounts: # 2
        - mountPath: /var/www/_nuxt
          name: assets
      - name: web
        image: gihyodocker/todoweb:latest
        imagePullPolicy: Always
        lifecycle: # 3
          postStart:
            exec:
              command:
              - cp
              - -R
              - /todoweb/.nuxt/dist
              - /
        ports:
        - containerPort: 3000
        env:
        - name: TODO_API_URL
          value: http://todoapi
        volumeMounts: # 4
        - mountPath: /dist
          name: assets

주의해서 볼 부분

#1 : assets라는 이름의 볼륨 생성. emptyDir로 설정해 파드 단위로 할당되는 가상 볼륨 생성.

#2 & #4 : 1에서 만든 볼륨을 각각의 컨테이너의 어느 위치에 마운트시킬지 설정

#3 : 초기에 이 볼륨은 빈 디렉터리이므로, 컨테이너 시작 직후에 값을 넣어줄 필요가 있음. lifecycle 이벤트를
이용해 이 작업을 실행

06. 인그레스로 웹 애플리케이션 노출하기

인그레스(ingress)

인그레스 또한 쿠버네티스 리소스 중 하나이므로 매니페스트 파일로 간단하게 인그레스를 클러스터에 반영할 수 있다.
ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress
spec:
  rules:
  - http:
      paths:
      - path: /*
        backend:
          serviceName: todoweb
          servicePort: 80

어떤 서비스의 어떤 포트를 외부에 노출시킬 지에 대한 것을 rules 필드 내에서 정의할 수 있고, 이를 클러스터에 적용한 후 할당받은 글로벌 IP 주소는
todoweb으로 연결된다.
GCP 콘솔을 보면 지금껏 만든 서비스 및 인그레스를 확인할 수 있고, 인그레스에 할당되어 있는 엔드포인트로 접속해보면 정상적으로 투두리스트가 잘 뜨는 것을 확인할 수 있다.

profile
서울대학교 컴퓨터공학부 github.com/BaekGeunYoung

0개의 댓글