티스토리 뷰

반응형

실 업무에 사용해보는 Kubernetes (공진기 - IBM)

github(jgkong/kubernetes-handson) : https://github.com/jgkong/kubernetes-handson

developerWorks에 정리해서 업로드 예정

Build and run

Create simple page

jgkong/kubernetes-handson
developerWorks에 정리해서 업로드 예정

# nginx 실행을 위한 기본 html 파일 작성
mkdir web
cd web
echo "<h1>Hello Kubernetes</h1>" > index.html
cat index.html

# Dockerfile 작성
cat > Dockerfile << _EOF_
FROM nginx:alpine
COPY index.html /usr/share/nginx/html/
_EOF_
cat Dockerfile

# Docker 이미지 빌드
docker build -t registry.au-syd.bluemix.net/jgkong/simplehome .

# simplehome 이미지를 기반으로 simplehome1 컨테이너 실행
docker run -d --rm --name simplehome1 -p 8080:80 registry.au-syd.bluemix.net/jgkong/simplehome

# http://localhost:8080 확인

# simplehome1 컨테이너 중지
docker stop simplehome1


Push image to IBM Cloud Container Registry

# IBM 클라우드 레지스트리가 아닌 자신의 DockerHub에 push해도 됨
# IBM 클라우드(BlueMix) 명령어
bx login
bx cr region-set ap-south
bx cr login
docker push registry.au-syd.bluemix.net/jgkong/simplehome


Run on IBM Cloud Kubernetes Service

# 지역 설정
bx cs region-set ap-north

# 클러스터 설정
bx cs clusters
bx cs cluster-config jgkong

# worker 노드의 설정 확인
bx cs workers jgkong
# 위에서 worker Public IP 확인

# pod 리스트 확인
kubectl get pod

# deployment 리스트 확인
kubectl get deployment
# 원격 환경으로 접속해서 Kubernetes 진행
export KUBECONFIG=/Users/arcturus/.bluemix/plugins/container-service/clusters/jgkong/kube-config-seo01-jgkong.yml

# deployment를 바로 만들어서 실행해줌
kubectl run simplehome --image=registry.au-syd.bluemix.net/jgkong/simplehome --port 80

# deployment 리스트 확인(에러 상태 확인)
kubectl get deployment
# deployment의 상세 설정 확인
kubectl describe deployment
# pod 리스트 확인(에러 상태 확인)
kubectl get pod
# pod 상세 정보 확인
kubectl describe pod

# simplehome 서비스 제거
kubectl delete service simplehome
# simplehome-nodeport 서비스 제거
kubectl delete service simplehome-nodeport

# simplehome deployment 제거
kubectl delete deployment simplehome


Expose service

# simlehome 서비스 생성
# 만들어진 Pod, ReplicaSet, Deployment, ...에 대해 외부에서 접속 가능하도록 서비스로 생성
kubectl expose deployment simplehome

# 서비스 리스트(상태) 확인
# CLUSTER-IP가 출력되는데, 클러스터끼리는 통신 가능
kubectl get service

# simplehome-nodeport 서비스 생성
# 외부에서 접속하기 위해 NodePort를 지정(30,000~32,.... 범위 내에서 자동으로 생성)
kubectl expose --name simplehome-nodeport deployment simplehome --type=NodePort
# 서비스 리스트(상태) 확인
kubectl get service

# 접속 확인
# http://<IP주소>:<NodePort번호>


Run with yaml

한 번에 여러 개를 정의 가능. 위에서 커맨드로 진행한 내용들을 yaml 파일로 한번에 진행.

cat > simplehome.yaml << _EOF_
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    run: simplehome
  name: simplehome
  namespace: default
spec:
  selector:
    matchLabels:
      run: simplehome
  template:
    metadata:
      labels:
        run: simplehome
    spec:
      containers:
      - image: registry.au-syd.bluemix.net/jgkong/simplehome
        name: simplehome
        ports:
        - containerPort: 80
          protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    run: simplehome
  name: simplehome
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: simplehome
  type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    run: simplehome
  name: simplehome-nodeport
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: simplehome
  type: NodePort
_EOF_
# simplehome.yaml 파일에서 정의한 내용 적용
kubectl apply -f simplehome.yaml

# delpoment 리스트(상태) 확인
kubectl get deployment
# pod 리스트(상태) 확인
kubectl get pod
# service 리스트(상태) 확인
kubectl get service

# http://<IP주소>:<NodePort번호> 페이지 확인

# simplehome.yaml에서 정의한 내용 모두 제거
kubectl delete -f simplehome.yaml
# simplehome.yaml 파일에서 정의한 내용 적용
kubectl apply -f simplehome.yaml


Ingress and TLS

'IP주소:포트번호'가 아닌 도메인에 적용하는 방법. Helm을 이용.


Init helm and install Ingress controller

https://github.com/kubernetes/ingress-nginx

https://github.com/kubernetes/charts/tree/master/stable/nginx-ingress

# helm 사용을 위해 init 명령 실행
helm init

# helm을 이용해 nginx로 구현된 ingress 컨트롤러 설치
# Worker 노드에 대한 IP 주소 설정 필요!! (공용IP 주소를 매핑)
helm install stable/nginx-ingress --name=nginx-ingress --namespace=kube-system --set rbac.create=true --set controller.service.externalIPs="{Worker Public IP,Worker Public IP}"

# home-ingress.yaml 파일 작성
cat > home-ingress.yaml << _EOF_
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myhome-ingress
spec:
  rules:
  - host: jgkong.seo01.containers.appdomain.cloud
    http:
      paths:
      - path: /
        backend:
          serviceName: simplehome
          servicePort: 80
_EOF_
  • host : 도메인명이 됨
  • serviceName : simplehome을 실행
  • 해당 도메인명으로 접속할 경우, simplehome 실행됨

-> http://jgkong.seo01.containers.appdomain.cloud/ 에서 확인


Create TLS certificates

# letsencrypt 디렉토리 생성(certbot 실행을 위해 필요)
mkdir -p letsencrypt/{etc,var/lib}

# 인증서를 받아오기 위한 certbot 실행(도메인 주인이 맞는지 확인해서 인증서 발행해줌)
docker run -it --rm --name certbot -v "$(pwd)/letsencrypt/etc:/etc/letsencrypt" -v "$(pwd)/letsencrypt/var/lib:/var/lib/letsencrypt" certbot/certbot certonly --server https://acme-v02.api.letsencrypt.org/directory --manual

# letsencrypt 인증서 생성을 위해 필요한 디렉토리 생성
mkdir -p .well-known/acme-challenge/
# .well-known/acme-challenge 디렉토리에 letsencrypt에서 요구하는 파일명, 파일내용 작성
echo "1gC_ahidUGBdOxNIhNWoTzbBTdn0K8f-axhIAczf_gc.JiWd-JcRdFtPARc5KelJvzhFDz0EdJm16uBuN0iiLaU" > .well-known/acme-challenge/1gC_ahidUGBdOxNIhNWoTzbBTdn0K8f-axhIAczf_gc

# 새로운 Docker 이미지 생성(COPY 명령에서 전체 디렉토리 복사하도록 수정)
docker build -t registry.au-syd.bluemix.net/jgkong/acme-challenge .
# Docker 이미지 push
docker push registry.au-syd.bluemix.net/jgkong/acme-challenge

# nginx 컨테이너 실행
kubectl run acme-challenge --image=registry.au-syd.bluemix.net/jgkong/acme-challenge --port 80

# 연결을 위해 acme-challenge 서비스 생성
kubectl expose deployment acme-challenge
# host를 추가 또는 수정해줌
kubectl edit ingress myhome-ingress
      - backend:
          serviceName: acme-challenge
          servicePort: 80
        path: /.well-known/acme-challenge
# letsencrypt에서 출력된 PATH로 접속 시, 파일 저장 창이 뜨는지 확인(떠야해!!!)
# 여기까지 완료 후, letsencrypt 인증서 생성 Continue

# key를 저장하는 simplehome-tls 생성
kubectl create secret tls simplehome-tls --key letsencrypt/etc/live/simplehome.arcy.me/privkey.pem --cert letsencrypt/etc/live/simplehome.arcy.me/fullchain.pem
# 생성된 simplehome-tls 확인
kubectl get secret simplehome-tls

# TLS 연결을 위해, ingress 편집
kubectl edit ingress myhome-ingress
  tls:
  - hosts:
    - simplehome.arcy.me
    secretName: simplehome-tls

https로 해당 페이지 접속을 확인합니다.


Cert-manager

도메인을 자동으로 만들어주는 차트

# ingress에서 TLS 관련 부분 삭제
kubectl edit ingress myhome-ingress
# key 값을 저장한 simplehome-tls 서비스 삭제
kubectl delete simplehome-tls

Cert-manager란? https://github.com/kubernetes/charts/tree/master/stable/cert-manager

# 
helm install --name cert-manager --namespace kube-system stable/cert-manager --set ingressShim.defaultIssuerName=letsencrypt-prod --set ingressShim.defaultIssuerKind=ClusterIssuer

# 인증서를 받기 위한 letsencrypt.yaml 파일 생성
cat > letsencrypt.yaml << _EOF_
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
  namespace: default
spec:
  acme:
    # The ACME server URL
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: jgkong@kr.ibm.com
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-staging
    # Enable the HTTP-01 challenge provider
    http01: {}

---
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
  namespace: default
spec:
  acme:
    # The ACME server URL
    server: https://acme-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: jgkong@kr.ibm.com
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-prod
    # Enable the HTTP-01 challenge provider
    http01: {}
_EOF_

# letsencrypt.yaml 파일 적용
kubectl apply -f letsencrypt.yaml

# annotations 추가를 위한 patch 명령 실행
kubectl patch ingress myhome-ingress -p='{"metadata": {"annotations": {"kubernetes.io/tls-acme": "true"}}}'
# spec에 TLS 추가를 위한 patch 명령 실행
kubectl patch ingress myhome-ingress -p='{"spec": {"tls": [{"hosts": ["simplehome.arcy.me"], "secretName": "simplehome-tls"}]}}'
# simplehome-tls 확인(생겼는지)
kubectl get secret
kubectl get secret simplehome-tls
# simplehome-tls 상세 확인
kubectl describe certificate simplehome-tls


Deployment control

Create frontend

# front-end Application을 실행하기 위핸 vue 생성
vue init pwa frontend
cd frontend
npm install

# 로컬에 페이지 생성
npm run dev
# http://localhost:8080 확인

# Hello.vue 파일 생성 확인
cat src/components/Hello.vue

# src/components/Hello.vue 파일 수정
cat > src/components/Hello.vue << _EOF_
<template>
  <div class="hello">
    <h1>Frontend version {{ frontVer }}</h1>
    <h1>Backend version {{ backVersion }}</h1>
  </div>
</template>

<script>
export default {
  name: 'hello',
  data () {
    return {
      frontVer: '1.0.0',
      backVersion: '0.0.0',
      hostname: 'computer'
    }
  }
}
</script>

<style>
</style>
_EOF_

# src/components/Hello.vue 작성 확인
cat src/components/Hello.vue

# 수정한 내용 적용을 위해 build 명령 실행
npm run build
# dist 디렉토리에 배포할 수 있도록...
ls dist

# Dockerfile 작성
cat > Dockerfile << _EOF_
FROM nginx:alpine
COPY dist/ /

# Dockerfile 작성 확인
cat Dockerfile

# Docker 이미지 빌드
docker build -t registry.au-syd.bluemix.net/jgkong/frontend:1 .
# 해당 이미지가 컨테이너로 잘 돌아가는지 확인
docker run -d --rm --name frontend1 -p 8080:80 registry.au-syd.bluemix.net/jgkong/frontend:1
# http://localhost:8080 확인
# 컨테이너가 정상적으로 돌아가는 것을 확인한 뒤, 해당 컨테이너 중지
docker stop frontend1
# 해당 이미지 push
docker push registry.au-syd.bluemix.net/jgkong/frontend:1
cd ..


Create backend server

# backend 부분 설정(server)
mkdir backend
cd backend
echo "{}" > package.json
npm install --save express

cat > app.js << _EOF_
let express = require('express')
let app = express()

app.get('/api', (req, res) => {
  res.send('This is backend base API server')
})

app.listen(3000, () => {
  console.log('app is running')
})
_EOF_


cat app.js
node app.js
# http://localhost:3000/api 접속
CTRL-C

# Dockerfile 작성(WORKDIR 설정)
cat > Dockerfile << _EOF_
FROM node:alpine
WORKDIR /app
EXPOSE 3000
CMD ["node", "app.js"]
COPY . .
_EOF_

cat Dockerfile
docker build -t registry.au-syd.bluemix.net/jgkong/baseapi:1 .
docker run -d --name baseapi1 -p 3000:3000 registry.au-syd.bluemix.net/jgkong/baseapi:1
http://localhost:3000/api 접속
docker stop baseapi1
docker push registry.au-syd.bluemix.net/jgkong/baseapi:1
cd ..


Deploy to Kubernetes

# Kubernetes로 실행을 위한 myhomepage.yaml 파일 작성
cat > myhomepage.yaml << _EOF_
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    run: frontend
  name: frontend
  namespace: default
spec:
  selector:
    matchLabels:
      run: frontend
  template:
    metadata:
      labels:
        run: frontend
    spec:
      containers:
      - image: registry.au-syd.bluemix.net/jgkong/frontend:1
        name: frontend
        ports:
        - containerPort: 80
          protocol: TCP
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    run: baseapi
  name: baseapi
  namespace: default
spec:
  selector:
    matchLabels:
      run: baseapi
  template:
    metadata:
      labels:
        run: baseapi
    spec:
      containers:
      - image: registry.au-syd.bluemix.net/jgkong/baseapi:1
        name: baseapi
        ports:
        - containerPort: 3000
          protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    run: frontend
  name: frontend
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: frontend
  type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    run: baseapi
  name: baseapi
spec:
  ports:
  - port: 3000
    protocol: TCP
    targetPort: 3000
  selector:
    run: baseapi
  type: ClusterIP
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myhomepage
spec:
  rules:
  - host: myhomepage.jgkong.seo01.containers.appdomain.cloud
    http:
      paths:
      - path: /
        backend:
          serviceName: frontend
          servicePort: 80
      - path: /api
        backend:
          serviceName: baseapi
          servicePort: 3000
_EOF_
# myhomepage.yaml 파일 작성 확인
cat myhomepage.yaml

# myhomepage.yaml 파일 적용(Application 실행)
kubectl apply -f myhomepage.yaml

http://myhomepage.jgkong.seo01.containers.appdomain.cloud/ 확인

http://myhomepage.jgkong.seo01.containers.appdomain.cloud/api/version 확인


Update baseapi server

cd baseapi
# app.js 추가(버전 정보 출력)
app.get('/api/version', (req, res) => {
  res.send('2.0.0')
})
perl -pi -e 's/1\.0\.0/2.0.0/' app.js

# Docker 이미지 빌드 및 push
docker build -t registry.au-syd.bluemix.net/jgkong/baseapi:2 .
docker push registry.au-syd.bluemix.net/jgkong/baseapi:2

# kubectl set image 명령을 통해 baseapi의 컨테이너 이미지 태그(버전)를 업데이트
kubectl set image --record deployment baseapi baseapi=registry.au-syd.bluemix.net/jgkong/baseapi:2
# rollout 상태 확인
kubectl rollout status deployment baseapi
kubectl rollout history deployment baseapi

# http://myhomepage.jgkong.seo01.containers.appdomain.cloud/api/version 확인
cd ..


Update frontend

cd frontend
# src/components/Hello.vue 추가
  created () {
    fetch('/api/version')
      .then(res => res.text())
      .then(res => {
        this.backVersion = res
      })
  }
# 수정된 내용 적용을 위해 build 명령 실행
npm run build

# Docker 이미지 빌드
docker build -t registry.au-syd.bluemix.net/jgkong/frontend:2 .

# 
kubectl rollout undo deployment baseapi

kubectl set image --record deployment frontend frontend=registry.au-syd.bluemix.net/jgkong/frontend:2
# rollout 결과 확인
kubectl rollout status deployment frontend 후 CTRL-C
kubectl get deployment
kubectl get replicaset
kubectl get pod
kubectl rollout history deployment frontend
kubectl rollout undo deployment frontend
kubectl rollout status deployment frontend
kubectl rollout history deployment frontend
kubectl get deployment
kubectl get replicaset
kubectl get pod


Modify RollingUpdateStrategy

kubectl describe deployment frontend
kubectl get deployment frontend -o json
kubectl patch deployment frontend -p='{"spec": {"strategy": {"rollingUpdate": {"maxUnavailable": 0}}}}'
kubectl describe deployment frontend
kubectl set image --record deployment frontend frontend=registry.au-syd.bluemix.net/jgkong/frontend:2
kubectl get replicaset
docker push registry.au-syd.bluemix.net/jgkong/frontend:2


Rollout by kubectl apply

src/components/Hello.vue 추가

    <h2>at {{ hostname }}</h2>
    fetch('/api/hostname')
      .then(res => res.text())
      .then(res => {
        this.hostname = res
      })
perl -pi -e 's/2\.0\.0/3.0.0/' src/components/Hello.vue
npm run build
docker build -t registry.au-syd.bluemix.net/jgkong/frontend:3 .
docker push registry.au-syd.bluemix.net/jgkong/frontend:3
cd ../backend/
# app.js 추가

app.get('/api/hostname', (req, res) => {
  res.send(require('os').hostname())
})


반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함