diff --git a/README.md b/README.md new file mode 100644 index 0000000..60b1528 --- /dev/null +++ b/README.md @@ -0,0 +1,97 @@ +# 본 과정에 대해 ( Cloud Native 입문 과정 ) + +본 교육 과정은 Cloud Native 입문 과정으로 이론 및 실습을 수행한다. + + +문의 : 이석환 ( seokhwan.lee@kt.com / shclub@gmail.com ) + +
+ +1. Chapter 1 : 2시간 ( [가이드 문서보기](./chapter1.md) ) + + - Docker 이해 및 활용 + - GitHub , Docker 계정 생성 , Jenkins Pipeline 생성하여 CI 실습 + - Swagger 설명 + - 샘플 소스 : [ 소스 보기 ](https://github.com/shclub/edu2) + +
+ +2. Chapter 2 : 2시간 ( [가이드 문서보기](./chapter2.md) ) + + - Github Action , workflow 사용 ( GoodBye Jenkins ) + - Docker Compose 설치 및 활용 ( DB 연동 ) + - 샘플 소스 : [ 소스 보기 ](https://github.com/shclub/edu1) + + +
+ +3. Chapter 3 : 2시간 ( [가이드 문서보기](./chapter3.md) ) + + - k8s 이해 및 활용 + - k8s hands-on Basic [ Hands-On 문서보기 ](./k8s_basic_hands_on.md) + + - 실습 전체 개요 + - kubeconfig 설정 : kubectl 설치 + - kubectl 활용 + - kubernetes 리소스 ( Pod , Service , Deployment 생성 및 삭제) + - 배포 ( Rolling Update / Rollback ) + - Serivce Expose ( Ingress / Route ) + +
+ +4. Chapter 4 : 2시간 ( [가이드 문서보기](./chapter4.md) ) + + - GitOps 설명 + - ArgoCD 설치 및 설정 + - kustomize 설명 및 실습 + - k8s에 배포 실습 ( Blue/Green , Canary ) + - ArgoCD Hands-on [ Hands-On 문서보기 ](./argocd_hands_on.md) + + - kubectl plugin 설치 + - Blue/Green 배포 + - Canary 배포 + - ArgoCD 계정 추가 및 권한 할당 + - kustomize 사용법 + - ArgoCD remote Cluster 에서 배포 하기 + +
+ +
+ +## Jenkins 접속 정보 + +
+ +```bash +http://211.252.85.148:9000/ +``` + +
+ +## OKD 접속 정보 + +
+ +```bash +oc login https://api.211-34-231-81.nip.io:6443 -u shclub-admin -p New1234! --insecure-skip-tls-verify +``` + +
+ +## Node Port용 접속 정보 + +
+ +```bash +211.34.231.84 +``` + +
+ +## ArgoCD 접속 정보 + +
+ +```bash +https://211.252.87.34:30000/ +``` diff --git a/argocd_hands_on.md b/argocd_hands_on.md new file mode 100644 index 0000000..3593545 --- /dev/null +++ b/argocd_hands_on.md @@ -0,0 +1,1141 @@ +# ArgoCD Hands-on + +ArgoCD 활용 방법에 대해서 실습한다. + +1. kubectl plugin 설치 + +2. Blue/Green 배포 + +3. Canary 배포 + +4. ArgoCD 계정 추가 및 권한 관리 + +5. kustomize 사용법 + +6. ArgoCD remote Cluster 에서 배포 하기 + +7. 참고 사이트 + - https://potato-yong.tistory.com/138 + - https://teichae.tistory.com/entry/Argo-CD%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-BlueGreen-%EB%B0%B0%ED%8F%AC-3 + - canary : https://teichae.tistory.com/entry/Argo-CD%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-Canary-%EB%B0%B0%ED%8F%AC-4 + +
+ +## 실습 전체 개요 + + +
+ +### kubectl plugin 설치 + +
+ +Argo Rollout 기능을 사용하기 위해서 kubectl plugins을 설치한다. + +- Mac + ```bash + brew install argoproj/tap/kubectl-argo-rollouts + ``` + +- linux ( ubuntu ) + ```bash + root@jakelee:~# curl -LO https://github.com/argoproj/argo-rollouts/releases/latest/download/kubectl-argo-rollouts-linux-amd64 + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed + 100 166 100 166 0 0 5187 0 --:--:-- --:--:-- --:--:-- 5187 + 100 672 100 672 0 0 17684 0 --:--:-- --:--:-- --:--:-- 17684 + 100 76.7M 100 76.7M 0 0 156M 0 --:--:-- --:--:-- --:--:-- 399M + ``` + + chmod로 권한을 부여하고 /usr/local/bin 폴더로 이동한다. + + ```bash + root@jakelee:~# chmod +x ./kubectl-argo-rollouts-linux-amd64 + root@jakelee:~# sudo mv ./kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts + ``` + +설치가 완료되고 나서 버전을 확인 한다. + +```bash +root@jakelee:~# kubectl argo rollouts version +kubectl-argo-rollouts: v1.2.0+08cf10e + BuildDate: 2022-03-22T00:25:11Z + GitCommit: 08cf10e554fe99c24c8a37ad07fadd9318e4c8a1 + GitTreeState: clean + GoVersion: go1.17.6 + Compiler: gc + Platform: linux/amd64 +``` + +
+ +### Blue/Green 배포 + +
+ +Blue/Green 배포란? + +참고 : https://youtu.be/qLlo7MAJvT0 + +
+ +Blue-Green 배포는 애플리케이션 또는 마이크로서비스의 이전 버전에 있던 사용자 트래픽을 이전 버전과 거의 동일한 새 버전으로 점진적으로 이전하는 애플리케이션 릴리스 모델입니다. 이때 두 버전 모두 프로덕션 환경에서 실행 상태를 유지합니다. + +이전 버전을 blue 환경으로, 새 버전은 green 환경으로 부를 수 있습니다. 프로덕션 트래픽이 blue에서 green으로 완전히 이전되면, blue는 롤백에 대비하여 대기 상태로 두거나 프로덕션에서 가져온 후 업데이트하여 다음 업데이트의 템플릿으로 삼을 수 있습니다. + +이와 같은 지속적 배포 모델에는 단점이 있습니다. 환경에 따라서는 업타임 요구 사항이 다르거나 blue-green과 같은 CI/CD 프로세스를 제대로 수행할 리소스가 없을 수도 있습니다. +그러나 애플리케이션을 지원하는 기업의 디지털 트랜스포메이션이 본격화되면서 많은 애플리케이션이 이러한 지속적 제공을 지원하도록 진화하고 있습니다. + +
+ +기존의 Kubernetes에서도 Deployment 2개를 생성하고 Service의 Selector를 변경해주는 방법으로 Blue/Green 방식의 배포를 할 수 있다. +하지만 이러한 방법은 Deployment 2개를 운영해야 하기 때문에 번거롭기도 하고 ArgoCD를 사용하면 더 편리하게 Blue/Green 방식으로 배포할 수 있다. + + + +기존 Kubernetes에서는 1개의 Pod가 각각 Rolling Update 방식으로 배포된다. + +1. Blue (2) - Green (0) +2. Blue (1) - Green (1) <- 이 단계에서 이전 버전과 새로운 버전이 공존하는 현상이 나타남 +3. Blue (0) - Green (2) + +이러한 방식을 Blue/Green 방식으로 배포하게 되면, +1. Blue (2) - Green (0) +2. Blue (2) - Green (2) <- 이 단계에서 총 4개의 파드가 생성되면서 Green 으로 옮겨간다 +3. Blue (0) - Green (2) + + +아래 예제를 사용하여 Blue/Green 배포할 Rollout과 Service를 생성합니다. + +https://github.com/shclub/edu5/blob/master/rollout/blue_green_test.yaml + +예제로 보는 Rollout의 yaml파일을 보면 Deployment와 거의 흡사하다. +여기서 살펴봐야 할 부분은 strategy 옵션과 새로 생성한 2개의 서비스들이다. + +Rollout은 2개의 서비스를 이용해 preview와 active로 나누어서 Blue와 Green을 구분하며, +active 에서는 blue가 보이고, preview에서는 green이 보이게 지정한다. + +autoPromotionEnabled 옵션은 자동으로 배포할 것인지, 관리자가 수동으로 승인할 것인지에 대한 여부를 묻는 옵션이다. + +본 가이드에서는 kubectl plugin을 설치했으니, 승인 과정까지 보여드리기 위해 autoPromotionEnabled: false로 진행했습니다. + +Blue/Green을 배포할 예제 yaml 파일이 준비가 되었다면, 이제 Argo CD에서 배포를 해보자. + +blue_green_test 라는 이름으로 yaml 파일이 저장된 레포지토리를 지정해서 새로운 애플리케이션을 배포해주자. + + +```bash +# ArgoCD Blue/Green 배포 예제 + +apiVersion: argoproj.io/v1alpha1 # apps/v1 대신 argoproj.io/v1alpha1을 사용한다 +kind: Rollout # Deployment 대신 Rollout을 사용한다 +metadata: + name: rollout-bluegreen +spec: + replicas: 2 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-bluegreen + template: + metadata: + labels: + app: rollout-bluegreen + spec: + containers: + - name: rollouts-demo + image: argoproj/rollouts-demo:blue + #image: argoproj/rollouts-demo:green + imagePullPolicy: Always + ports: + - containerPort: 8080 + strategy: + blueGreen: + #activeService는 이전의 배포된 Blue 서비스 + activeService: rollout-bluegreen-active + + #previewService는 새롭게 배포될 Green 서비스 + previewService: rollout-bluegreen-preview + + #autoPromotioEnabled 옵션은 Blue/Green 배포를 자동으로 진행할 것인지 여부. false 옵션을 사용해 수동으로 지정 + autoPromotionEnabled: false +``` + +ArgoCD에서 New App를 클릭하고 아래와 같이 설정하고 Create 한다. +namespace 는 rollout-demo로 자동 생성되게 설정한다. + + + + +배포가 정상적으로 되었는지 확인한다. + + + +아래 명령어를 사용하여 서비스의 NodePort를 확인한다. + +```bash +root@jakelee:~# kubectl get all -n rollout-demo +NAME READY STATUS RESTARTS AGE +pod/rollout-bluegreen-5ffd47b8d4-zlkfl 1/1 Running 0 16s +pod/rollout-bluegreen-5ffd47b8d4-rttxs 1/1 Running 0 16s + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +service/rollout-bluegreen-preview NodePort 10.43.4.240 80:30082/TCP 16s +service/rollout-bluegreen-active NodePort 10.43.213.203 80:30081/TCP 16s + +NAME DESIRED CURRENT READY AGE +replicaset.apps/rollout-bluegreen-5ffd47b8d4 2 2 2 16s +``` + +Blue Green이 배포되었으니 확인하기 위해서 active와 preview 서비스의 노드 포트를 통해서 접속해보자. + +- active 접속 : ( 서버 IP ) :30081 +- preview 접속 : ( 서버 IP ) :30082 + +배포를 진행하고 active 서비스로 접속을 해보면 Blue 페이지가 표시되는 것을 확인할 수 있다. + +현재는 blue만 배포되어 있기 때문에 active와 preview 둘다 blue만 보일것이다. + + + +다음으로 이전에 배포했던 yaml파일에서 주석처리 되어있던 Green 이미지를 사용하여 다시 재배포해주자. + + + +그리고 실행되고 있는 pod를 확인해보면 총 4개의 pod가 생성되어 있고, 먼저 생성된 것이 blue, 나중에 새로 생겨난것이 green이다. + +여기까지 진행하면 active에는 blue가 배포 되어있고, preview에 green이 배포되어 있는것을 직접 확인할 수 있다. + + + +```bash +root@jakelee:~# kubectl get po -n rollout-demo +NAME READY STATUS RESTARTS AGE +rollout-bluegreen-5ffd47b8d4-zlkfl 1/1 Running 0 11m +rollout-bluegreen-5ffd47b8d4-rttxs 1/1 Running 0 11m +rollout-bluegreen-75695867f-mnblz 1/1 Running 0 50s +rollout-bluegreen-75695867f-rxw9k 1/1 Running 0 50s +``` + +preview에 접속해보면 green 변경 된것을 확인 할수 있다. active는 현재 blue 이다. + + + +
+ +Blue/Green 교체 승인 + +Blue/Green yaml 파일에서 autoPromotionEnabled 옵션을 false로 주었기 때문에 Blue에서 Green으로 자동으로 배포되지 않고 정지되어 있는 상태를 확인할 수 있다. + +이후, 정상적으로 Blue/Green이 배포된것을 확인했다면 Green으로 교체해주는 과정을 진행해주어야 한다. + +- argocd ui에서 진행하는 방법 + + rollout 화면에서 파란색 아이콘으로 paused 된 상태를 볼수 있고 오른쪽 점 표시를 클릭하면 여러가지 메뉴를 볼수 있는데 승인을 하기 위해서는 resume을 클릭한다. + + + + 실행을 하기 위해서 OK를 클릭한다. + + + +- 명령 모드 에서 진행하는 방법 + ```bash + #rollout 상태 확인 : STATUS는 Paused + root@jakelee:~# kubectl argo rollouts list rollout -n rollout-demo + NAME STRATEGY STATUS STEP SET-WEIGHT READY DESIRED UP-TO-DATE AVAILABLE + rollout-bluegreen BlueGreen Paused - - 2/4 2 2 2 + ``` + + rollout 상태 확인 후 승인 + + ```bash + #rollout 상태 확인 후 승인 + root@jakelee:~# kubectl argo rollouts promote rollout-bluegreen -n rollout-demo + rollout 'rollout-bluegreen' promoted + ``` + +rollout 상태 확인 + +```bash +#rollout 상태 확인 (healthy) +root@jakelee:~# kubectl argo rollouts list rollout -n rollout-demo +NAME STRATEGY STATUS STEP SET-WEIGHT READY DESIRED UP-TO-DATE AVAILABLE +rollout-bluegreen BlueGreen Healthy - - 2/4 2 2 2 +``` + +promote 과정을 진행하면 rollouts의 상태가 healthy로 변하고 blue 배포되었던 pod가 종료된다. + +```bash +#pod 상태 확인 (healthy) +root@jakelee:~# kubectl get po -n rollout-demo +NAME READY STATUS RESTARTS AGE +rollout-bluegreen-75695867f-mnblz 1/1 Running 0 10m +rollout-bluegreen-75695867f-rxw9k 1/1 Running 0 10m +rollout-bluegreen-5ffd47b8d4-zlkfl 1/1 Terminating 0 20m +rollout-bluegreen-5ffd47b8d4-rttxs 1/1 Terminating 0 20m +root@jakelee:~# kubectl get po -n rollout-demo +NAME READY STATUS RESTARTS AGE +rollout-bluegreen-75695867f-mnblz 1/1 Running 0 13m +rollout-bluegreen-75695867f-rxw9k 1/1 Running 0 13m +``` + +이때 다시 active와 preview 로 접속해보면 모두 Green으로 표시되고 무사히 Blue에서 Green으로 교체되는 모습을 볼 수 있다. + + + +
+ +### Canary 배포 + +
+ +Canary 배포란? + +Canary 배포는 기존에 배포된 서비스에 신규 서비스를 한꺼번에 배포/교체를 진행하지 않고 소량의 Pod만 일시적으로 배포하는 방식입니다. + +Canary 방식의 어원을 살펴보자면, `카나리아`라는 새에서 나오게 되었다. + + +`카나리아는 메탄, 일산화탄소에 매우 민감한 새라 가스에 노출되면 죽어버리게 된다. 그래서 옛날에 광부들이 안전하게 일 할 수 있도록 카나리아를 이용하였다. 카나리아가 노래를 계속하고 있는 동안 광부들은 안전함을 느낀 채 일 할 수 있었으며, 만약 카나리아가 죽게 되면 곧바로 탄광을 탈출함으로써 광부들의 생명을 보존할 수 있었다.` + +Canary 방식은 카나리아 새처럼 위험을 빠르게 감지할 수 있는 방식이다. + +특정 서버나 소수의 유저들만 먼저 새로운 버전을 배포하고 사용하고 나서 안전하다고 판단이 되면 그 후에 모든 서버들에 새로운 버전을 배포하는 방식이다. + + + +배포를 위한 소스는 아래 와 같습니다. nodeport는 blue/green 예제와 충돌 나지 않도록 30083을 사용합니다. + +- 소스 : https://github.com/shclub/edu5/blob/master/canary/canary.yaml + +```bash +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: canary-rollout +spec: + replicas: 8 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: canary + template: + metadata: + labels: + app: canary + spec: + containers: + - name: canary-rollouts-demo + image: particule/simplecolorapi:1.0 + imagePullPolicy: Always + ports: + - containerPort: 5000 + strategy: + canary: + maxSurge: "25%" + maxUnavailable: 0 + steps: + - setWeight: 25 + - pause: {} +--- +kind: Service +apiVersion: v1 +metadata: + name: canary-service +spec: + selector: + app: canary + ports: + - protocol: TCP + port: 80 + targetPort: 5000 + nodePort: 30083 + type: NodePort +``` + +아래는 옵션 설명입니다. + +```bash + strategy: + canary: + maxSurge: "25%" + maxUnavailable: 0 + steps: + - setWeight: 25 + - pause: {} +``` + +maxSurge는 배포되는 Pod의 비율을 뜻하고, maxUnavailable는 배포될 때 Unavailable되도 되는 Pod의 수를 뜻합니다. + +steps에서 setWeight는 Weight 값을 주어 트래픽을 어느 정도 인가하는지에 대한 옵션입니다. + +pause는 Blue/Green 처럼 AutoPromotion Time을 뜻합니다. + +아래와 같이 시간을 지정할 수 있습니다. + +```bash + - pause: { duration: 10 } # 10초 + - pause: { duration: 10s } # 10초 + - pause: { duration: 10m } # 10분 + - pause: { duration: 10h } # 10시간 + - pause: { duration: -10 } # 잘못된 옵션 + - pause: {} # Auto Promotion 옵션 비활성화 +``` + +New App으로 새로운 배포 구성을 합니다. 설정은 Blue/Green을 참고하고 path는 ./canary로 설정한다. + + + + +실행을 하면 pod가 8개가 생성된것을 확인 할 수 있다. + + + +배포가 완료되었습니다. Canary page에 접속해보겠습니다. +Red라는 응답값이 나오게 됩니다. + + + +이제 2.0 버전의 이미지를 배포하여, 25%의 배포 및 트래픽 인가를 해보겠습니다. + +코드는 아래처럼 배포할 이미지 태그를 수정하면 됩니다. + + + +배포 후 신규 Replicaset이 생성되며 8개의 Pod의 25%니까 2개가 새로 배포된 것을 확인할 수 있습니다. + + + +원활한 테스트를 진행하기 위해 커맨드라인 JSON 파서인 jq 라이브러리를 설치합니다. + +```bash +root@jakelee:~# apt install jq +Reading package lists... Done +Building dependency tree +Reading state information... Done +The following additional packages will be installed: + libjq1 libonig4 +The following NEW packages will be installed: + jq libjq1 libonig4 +0 upgraded, 3 newly installed, 0 to remove and 4 not upgraded. +Need to get 276 kB of archives. +After this operation, 930 kB of additional disk space will be used. +Do you want to continue? [Y/n] Y +Get:1 http://kr.archive.ubuntu.com/ubuntu bionic/universe amd64 libonig4 amd64 6.7.0-1 [119 kB] +Get:2 http://kr.archive.ubuntu.com/ubuntu bionic/universe amd64 libjq1 amd64 1.5+dfsg-2 [111 kB] +Get:3 http://kr.archive.ubuntu.com/ubuntu bionic/universe amd64 jq amd64 1.5+dfsg-2 [45.6 kB] +Fetched 276 kB in 2s (117 kB/s) +Selecting previously unselected package libonig4:amd64. +(Reading database ... 147313 files and directories currently installed.) +Preparing to unpack .../libonig4_6.7.0-1_amd64.deb ... +Unpacking libonig4:amd64 (6.7.0-1) ... +Selecting previously unselected package libjq1:amd64. +Preparing to unpack .../libjq1_1.5+dfsg-2_amd64.deb ... +Unpacking libjq1:amd64 (1.5+dfsg-2) ... +Selecting previously unselected package jq. +Preparing to unpack .../jq_1.5+dfsg-2_amd64.deb ... +Unpacking jq (1.5+dfsg-2) ... +Setting up libonig4:amd64 (6.7.0-1) ... +Setting up libjq1:amd64 (1.5+dfsg-2) ... +Setting up jq (1.5+dfsg-2) ... +Processing triggers for man-db (2.8.3-2ubuntu0.1) ... +Processing triggers for libc-bin (2.27-3ubuntu1.5) ... +``` + +0.5초마다 curl을 실행하여 테스트할 때, 정상적으로 Canary 배포가 되어 있는 점을 확인할 수 있습니다. + +아래 구문에서 ip는 본인 VM Public IP를 사용합니다. + +```bash +root@jakelee:~# while true; do curl http://210.106.105.165:30083 | jq .color; sleep 0.5; done +``` + + + + +배포가 정상적으로 이루어졌고, canary 버전이 문제가 없기 때문에 기존에 배포된 내용을 걷어내고, canary 버전을 완전히 배포해보겠습니다. + +```bash +root@jakelee:~# kubectl argo rollouts list rollout -n canary +NAME STRATEGY STATUS STEP SET-WEIGHT READY DESIRED UP-TO-DATE AVAILABLE +canary-rollout Canary Paused 1/2 25 8/8 8 2 8 +``` + +Blue/Green 때처럼 Status가 Pause 상태인 것을 확인할 수 있습니다. + +Promote명령어를 이용하여 배포를 진행합니다. + +```bash +root@jakelee:~# kubectl argo rollouts promote canary-rollout -n canary +rollout 'canary-rollout' promoted +root@jakelee:~# kubectl argo rollouts list rollout -n canary +NAME STRATEGY STATUS STEP SET-WEIGHT READY DESIRED UP-TO-DATE AVAILABLE +canary-rollout Canary Progressing 2/2 100 8/10 8 4 8 +root@jakelee:~# kubectl argo rollouts list rollout -n canary +NAME STRATEGY STATUS STEP SET-WEIGHT READY DESIRED UP-TO-DATE AVAILABLE +canary-rollout Canary Progressing 2/2 100 8/10 8 6 8 +root@jakelee:~# kubectl argo rollouts list rollout -n canary +NAME STRATEGY STATUS STEP SET-WEIGHT READY DESIRED UP-TO-DATE AVAILABLE +canary-rollout Canary Progressing 2/2 100 8/10 8 8 8 +root@jakelee:~# kubectl argo rollouts list rollout -n canary +NAME STRATEGY STATUS STEP SET-WEIGHT READY DESIRED UP-TO-DATE AVAILABLE +canary-rollout Canary Healthy 2/2 100 8/8 8 8 8 +``` + +배포가 완료되고 Status가 Healthy로 변경된 것을 확인할 수 있습니다. + + + +다시 한번 0.5초마다 curl을 실행하여 하여 보면 모두 blue로 변경된걸 확인 할 수 있다. + +```bash +root@jakelee:~# while true; do curl http://210.106.105.165:30083 | jq .color; sleep 0.5; done +``` + + + + + +
+ +### ArgoCD 계정 추가 + +
+ +ArgoCD 신규 계정을 생성한다. GUI에서는 불가능하고 argocd cli를 사용한다. + +argocd-server의 서비스 IP를 확인한다. + +```bash +oot@jakelee:~# kubectl get svc -n argocd +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +argocd-applicationset-controller ClusterIP 10.43.26.65 7000/TCP 12d +argocd-dex-server ClusterIP 10.43.239.221 5556/TCP,5557/TCP,5558/TCP 12d +argocd-metrics ClusterIP 10.43.251.44 8082/TCP 12d +argocd-notifications-controller-metrics ClusterIP 10.43.214.197 9001/TCP 12d +argocd-redis ClusterIP 10.43.12.131 6379/TCP 12d +argocd-repo-server ClusterIP 10.43.132.197 8081/TCP,8084/TCP 12d +argocd-server-metrics ClusterIP 10.43.200.82 8083/TCP 12d +argocd-server NodePort 10.43.247.167 80:30000/TCP,443:30001/TCP 12d +inspekt ClusterIP 10.43.156.159 80/TCP 3d17h +``` + +cluster ip로 로그인 한다. + +```bash +root@jakelee:~# argocd login 10.43.247.167 +WARNING: server is not configured with TLS. Proceed (y/n)? y +Username: admin +Password: +'admin:login' logged in successfully +Context '10.43.247.167' updated +``` + +새로운 account 는 shclub 입니다. + +ArgoCD 의 account 추가는 ArgoCD의 Configmap을 통해서 가능합니다. + +아래 명령을 실행 합니다. + + +```bash +root@jakelee:~# kubectl -n argocd edit configmap argocd-cm -o yaml +apiVersion: v1 +data: + accounts.shclub: apiKey,login +kind: ConfigMap +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"v1","kind":"ConfigMap","metadata":{"annotations":{},"labels":{"app.kubernetes.io/name":"argocd-cm","app.kubernetes.io/part-of":"argocd"},"name":"argocd-cm","namespace":"argocd"}} + creationTimestamp: "2022-04-01T08:31:45Z" + labels: + app.kubernetes.io/name: argocd-cm + app.kubernetes.io/part-of: argocd + name: argocd-cm + namespace: argocd + resourceVersion: "903340" + uid: 1ea9382d-052b-43e9-b1b4-6d212efee1ec +``` +계정을 생성하기 위해 2개 라인을 추가합니다. +아래에서 shclub는 추가할 계정이름이다. 본인의 계정으로 설정. + +```bash +data: + accounts.shclub: apiKey,login +``` + +계정 리스트를 통해 신규 계정 생성을 확인합니다. + +```bash +root@jakelee:~# argocd account list +NAME ENABLED CAPABILITIES +admin true login +shclub true apiKey, login +root@jakelee:~# argocd account get --account shclub +Name: shclub +Enabled: true +Capabilities: apiKey, login + +Tokens: +NONE +``` + +비밀번호를 변경합니다. 8자리 이상으로 설정. + +```bash +root@jakelee:~# argocd account update-password --account shclub +*** Enter password of currently logged in user (admin): +*** Enter new password for user shclub: +*** Confirm new password for user shclub: +Password updated +``` + +해당 계정으로 로그인 하면 admin 계정으로 생성한 배포 pipeline을 볼 수 없습니다. + + + + +ArgoCD가 사용하는 RBAC 규칙에 맞게 새롭게 permission 을 할당해주어야 합니다. + +ArgoCD RBAC 을 추가하려면 ArgoCD Confimap 인 argocd-rbac-cm 을 수정해야 합니다. 다음 명령을 실행 하여 수정을 시작 합니다. + +shclub는 신규 생성한 계정이고 여러분의 계정으로 변경하여 저장하시면 됩니다. + +```bash +root@jakelee:~# kubectl -n argocd edit configmap argocd-rbac-cm -o yaml +apiVersion: v1 +data: + policy.csv: | + p, role:manager, applications, *, */*, allow + p, role:manager, clusters, get, *, allow + p, role:manager, repositories, *, *, allow + p, role:manager, projects, *, *, allow + g, shclub, role:manager + policy.default: role:readonly +kind: ConfigMap +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"v1","kind":"ConfigMap","metadata":{"annotations":{},"labels":{"app.kubernetes.io/name":"argocd-rbac-cm","app.kubernetes.io/part-of":"argocd"},"name":"argocd-rbac-cm","namespace":"argocd"}} + creationTimestamp: "2022-04-01T08:31:45Z" + labels: + app.kubernetes.io/name: argocd-rbac-cm + app.kubernetes.io/part-of: argocd + name: argocd-rbac-cm + namespace: argocd + resourceVersion: "904712" + uid: 5493d81d-74a4-4f55-830b-919a924d7440 +``` + +
+ +role은 manager 라는 이름으로 생성하였고 거의 full 권한을 가지고 있습니다. + +향후에 좀더 detail 하게 설정 할 수 있습니다. + +```bash +data: + policy.csv: | + p, role:manager, applications, *, */*, allow + p, role:manager, clusters, get, *, allow + p, role:manager, repositories, *, *, allow + p, role:manager, projects, *, *, allow + g, shclub, role:manager + policy.default: role:readonly +``` + +ArgoCD 화면에 admin 계정으로 생성한 pipeline 을 볼수 있습니다. + + + +
+ +운영 환경에서는 권한을 최소화 하여야 합니다. + +먼저 default 라고 하는 project 와는 별도로 신규 project를 생성합니다. + +아래 내용을 복사하고 vi 에디터로 argocd_proj.yaml 화일을 만들고 붙여 넣기 한 후 저장한다. + +
+ +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: edu-project + namespace: argocd +spec: + clusterResourceWhitelist: + - group: '*' + kind: '*' + destinations: + - namespace: '*' + server: '*' + orphanedResources: + warn: false + sourceRepos: + - '*' +``` + +
+ +아래 명령어를 사용하여 project를 생성한다. + +```bash +root@jakelee:~# kubectl apply -f argocd_proj.yaml +``` + +에러가 없이 발생하면 edu-project 라는 이름으로 project 가 생성된 것을 확인 할 수 있다. + +```bash +root@jakelee:~# kubectl get appproject -n argocd +NAME AGE +default 53d +edu-project 88m +``` + +
+ +아래 처럼 default role을 readonly에서 모든 기능을 disable 하도록 한다. + +기존 +```bash + policy.default: role:readonly +``` + +변경 +```bash + policy.default: role:'' +``` + +
+ +권한을 세부 적으로 컨트롤 한다. + +edu1 이라는 신규 생성은 edu-project라고 하는 project에 한하여만 전체 권한을 갖는다. + +edu-project 이외의 applications 들은 볼수 없습니다. + +```bash + p, role:edu1, clusters, get, *, allow + p, role:edu1, repositories, get, *, allow + p, role:edu1, projects, get, *, allow + p, role:edu1, applications, *, edu-project/*, allow +``` + +
+ +아래 처럼 프로젝트 명을 적어 주면 해당 프로젝트만 보입니다. + + +```bash + p, role:edu1, projects, get, edu-project, allow +``` + +
+ +전체 내용은 아래와 같다. + + +```bash +data: + policy.csv: | + p, role:manager, applications, *, */*, allow + p, role:manager, clusters, get, *, allow + p, role:manager, repositories, *, *, allow + p, role:manager, projects, *, *, allow + p, role:edu1, clusters, get, *, allow + p, role:edu1, repositories, get, *, allow + p, role:edu1, projects, get, *, allow + p, role:edu1, applications, *, edu-project/*, allow + g, edu1, role:edu1 + g, shclub, role:manager + policy.default: role:'' +``` + +
+ +### kustomize + +
+ +kustomize란? +- https://kubernetes.io/ko/docs/tasks/manage-kubernetes-objects/kustomization/ + +
+ +kubernetes의 배포 도구 중 하나로, kubectl v1.14에 통합되었음 + +기존에 helm chart를 통해 application 배포를 수행하였으나, helm value를 추가 하기 위해서는 helm template chart의 수정이 필요했음. + +kustomize는 기본적으로 사용되던 yaml을 그대로 사용하며, kustomization.yaml과 base, overay 및 production, development등 디렉토리를 환경에 맞게 구성하여 별도의 데이터 기반으로 배포 관리를 할수 있음. + +overlay는 패치가 필요한 쿠버네티스 리소스에는 변경하고자 하는 부분만 YAML로 만들어서 패치 형태로 쓸 수 있다. + + + + +
+base + +- 기본 yaml file들이 저장되는 경로 + - 해당폴더에 kustomization.yaml 파일이 필히 존재해야 함 +- https://github.com/kubernetes-sigs/kustomize#1-make-a-kustomization-file +- 기존에 사용되던 yaml파일들을 여기에 복사해두고 kustomization.yaml에 사용할 yaml을 선언해두면 된다. + + + + +
+ +overlays + +- 일반적으로 base에 사용되는 yaml을 기반으로 patch하여 업데이트 하는 방식으로 사용 +- 하위 디렉토리에서 느낄수 있듯이 stage 별로 나누거나 공용으로 사용되는 base에 특정한 value를 추가해야 하는 경우 사용된다. +- https://github.com/kubernetes-sigs/kustomize#2-create-variants-using-overlays +- overlays 하위에 디렉토리로 staging, dev, production 등 다양한 stage별 식별이 가능한 옵션을 두고 관리할수 있다. + + + + +
+테스트를 위한 config는 https://github.com/shclub/edu6 를 참고한다. + +현재 화일 구조는 아래와 같다. + +``` +├── base +│ ├── service.yaml +│ ├── deployment.yaml +│ ├── kustomization.yaml +└── overlays + └── development + ├── kustomization.yaml + └── cpu_count.yaml + └── replica_count.yaml + └── production + ├── kustomization.yaml + └── cpu_count.yaml + └── replica_count.yaml + +``` + +base 폴더의 kustomzation.yaml 화일 + +``` +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- deployment.yaml +- service.yaml +``` + +overlays/development 폴더의 kustomization.yaml 화일 +- namePrefix : pod의 이름 앞에 붙는다. + +``` +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: +- name: shclub/edu4 + newTag: v1 +namePrefix: dev- +bases: +- ../../base +patchesStrategicMerge: +- replica_count.yaml +- cpu_count.yaml +``` + +cpu_count.yaml 화일 +- cpu max 값 설정 + +``` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: edu6 +spec: + template: + spec: + containers: + - name: edu6 + resources: + limits: + cpu: 300m +``` + +replica_count.yaml 화일 +- replica 설정 + +``` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: edu6 +spec: + replicas: 2 +``` + +
+ +먼저 kustomize를 설치한다. + +아래 명령어 하나로 설치가 된다. + +```bash +root@jakelee:~# curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash + +{Version:kustomize/v4.5.4 GitCommit:cf3a452ddd6f83945d39d582243b8592ec627ae3 BuildDate:2022-03-28T23:12:45Z GoOs:linux GoArch:amd64} +kustomize installed to //root/kustomize +``` + +-bash: kustomize: command not found 에러가 발생하면 +아래 명령어를 실행한다. + +```bash +mv kustomize /usr/local/bin/ +``` + +우리는 ArgoCD를 통해서 kustomize를 연동하도록 한다. +ArgoCD에서 New App을 아래와 같이 만든다. + + + + +sync를 해보면 replica 2개로 설정되어 pod가 2개가 생성 된걸 볼수 있다. + + + +POD의 resource는 300m으로 최대값이 설정되어 있다. + + + +
+ +참고 : 명령어로 작업하기 + +
+kustomize 설정 확인. +github의 shclub/edu6에 설정 되어 있는 화일로 테스트 한다. +- git clone은 하고 다운받은 화일로 하면 됨. + +```bash +root@jakelee:~# kustomize build https://github.com/shclub/edu6/overlays/development/ +apiVersion: v1 +kind: Service +metadata: + name: dev-edu6 +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + run: edu6 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dev-edu6 +spec: + replicas: 2 + selector: + matchLabels: + run: edu6 + template: + metadata: + labels: + run: edu6 + spec: + containers: + - image: shclub/edu4:v1 + name: edu6 + ports: + - containerPort: 80 + resources: + limits: + cpu: 300m +``` + +kustomize 적용 + +```bash +kubectl apply -k https://github.com/shclub/edu6/overlays/development/ +``` + +
+ + +### argocd remote 에서 배포 하기 + +
+ +argocd 를 다른 cluster를 통해서 배포해 본다. + +접속하고자 하는 k8s cluster의 config 정보를 복사한다. + +.kube 폴더 밑에 config 화일을 하나 추가한다. + +vi 에디터로 사용한다. + +``` +root@jake-Wyse-mint2:~/.kube# vi config-epc-jakelee +``` + +복사한 config 화일 내용을 붙여넣기 한다. +아래는 샘플 내용이다. + +```bash +apiVersion: v1 +clusters: +- cluster: + certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1J-----SUJkekNDQVIyZ0F3SUJBZ0l + server: https://210.106.105.165:6443 + name: k3s-test +contexts: +- context: + cluster: k3s-test + user: k3s-test + name: k3s-test +current-context: k3s-test +kind: Config +preferences: {} +users: +- name: k3s-test + user: + client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FUZ0F3SUJBZ0lJTzJxVnRk-----0tLQo= +``` + +새로운 config을 /etc/profile 에 추가한다. + +```bash +root@jake-Wyse-mint2:~/.kube# vi /etc/profile +``` + +추가할 내용은 아래와 같다. + +```bash +export KUBECONFIG=/etc/rancher/k3s/k3s.yaml:/root/.kube/config-epc-jakelee:$KUBECONFIG +``` + +source 명령어를 사용하여 적용한다. + +```bash +root@jake-Wyse-mint2:~/.kube# source /etc/profile +``` + +정상적으로 추가가 된지 확인한다. + +```bash +root@jake-Wyse-mint2:~/.kube# kubectl config get-contexts +CURRENT NAME CLUSTER AUTHINFO NAMESPACE +* default default default + k3s-test k3s-test k3s-test +``` + +k3s-test 클러스터에 접속하기 위해서 context를 switch 해본다. + +```bash +root@jake-Wyse-mint2:~/.kube# kubectl config use-context k3s-test +Switched to context "k3s-test". +``` + +리모트 k8s 접속이 확인 되었으면 다시 로컬 클러스터로 switch 한다. + +```bash +root@jake-Wyse-mint2:~/.kube# kubectl config use-context default +Switched to context "default". +``` + +argo cd 에 cli 로 로그인 하기 위해서 서비스의 ip를 확인한다. ( 로컬 k8s 임 ) + +```bash +root@jake-Wyse-mint2:~/.kube# kubectl get svc -n argocd +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +argocd-dex-server ClusterIP 10.43.159.136 5556/TCP,5557/TCP,5558/TCP 69d +argocd-metrics ClusterIP 10.43.4.89 8082/TCP 69d +argocd-redis ClusterIP 10.43.124.226 6379/TCP 69d +argocd-repo-server ClusterIP 10.43.221.146 8081/TCP,8084/TCP 69d +argocd-server-metrics ClusterIP 10.43.148.232 8083/TCP 69d +argocd-server NodePort 10.43.188.106 80:32000/TCP,443:30904/TCP 69d +``` + +argocd server로 로그인한다. +insecurely 접속을 물어보면 y를 입력한다. + +```bash +root@jake-Wyse-mint2:~/.kube# argocd login 10.43.188.106 +WARNING: server certificate had error: x509: cannot validate certificate for 10.43.188.106 because it doesn't contain any IP SANs. Proceed insecurely (y/n)? y +Username: admin +Password: +``` + +cluster 추가 명령어는 아래와 같다. + +```bash +argocd cluster add <클러스터 이름 > +``` + +argocd에 외부 k8s cluster를 추가해 본다. + +```bash +root@jake-Wyse-mint2:~/.kube# argocd cluster add k3s-test +WARNING: This will create a service account `argocd-manager` on the cluster referenced by context `k3s-test` with full cluster level admin privileges. Do you want to continue [y/N]? y +INFO[0004] ServiceAccount "argocd-manager" created in namespace "kube-system" +INFO[0004] ClusterRole "argocd-manager-role" created +INFO[0004] ClusterRoleBinding "argocd-manager-role-binding" created +Cluster 'https://210.106.105.165:6443' added +``` + +
+ +web browser로 argocd ui 를 접속하여 setting-> Cluster 메뉴로 이동하면 cluster가 추가 된 것을 확인한다. + + + +배포 구성을 할때 remote 클러스터 선택 할 수 있다. + +
+ +### 참고 + +
+ +참고사이트 +- https://tech.kakao.com/2021/07/16/devops-for-msa/ +- https://velog.io/@wlgns5376/GitOps-ArgoCD와-Kustomize를-이용해-kubernetes에-배포하기 +- https://github.com/wlgns5376/example-app-kustomize/ +- https://asuraiv.tistory.com/22?category=877062 +- argocd 권한 : https://intrepidgeeks.com/tutorial/argocd-users-access-and-rbac +- k8s 전체 개념 :https://www.slideshare.net/gamzabaw/kubernetes-walkthrough + + +
+ +### Helm -> Kustomize 전환 + +
+ +Replicated의 쉽(Ship) 사용 + +이제, Helm을 Kustomize 형태로 변환하는 작업이 필요합니다. 이를 도와주는 도구가 쉽(Ship)입니다. + +https://www.replicated.com/ship/oss/ +https://github.com/replicatedhq/ship + + +- 먼저 Ship을 사용해 Helm을 템플릿화된 쿠버네티스 리소스 형태로 변경합니다. +- 이후 쿠버네티스 리소스에서 필요한 부분만 Kustomize 패치를 사용해 변경하고 변경한 부분은 GitOps 리포지토리에 넣어서 관리합니다. + +- GitOps 리포지토리에 `git push origin HEAD:install/ ${cluster}/${namespace}/${app_name}` 과 같은 Git CLI 명령을 통해 install 브랜치가 생성이 되면 해당 브랜치의 `${app_name}` 인프라를 배포하는 CI/CD 파이프라인이 실행됩니다. +- 배포의 형상은 마찬가지로 Argo CD를 통해 GitOps로 관리합니다. + +### 과제 + +
+ +과제 1 : kustomize를 production 에서 argocd로 배포 한다. + ( shclub/edu6/overlays/production 참고) \ No newline at end of file diff --git a/assets/.DS_Store b/assets/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/assets/.DS_Store differ diff --git a/assets/apt_update.png b/assets/apt_update.png new file mode 100644 index 0000000..e8ebf83 Binary files /dev/null and b/assets/apt_update.png differ diff --git a/assets/argo_rollouts_all.png b/assets/argo_rollouts_all.png new file mode 100644 index 0000000..df6d134 Binary files /dev/null and b/assets/argo_rollouts_all.png differ diff --git a/assets/argo_rollouts_install.png b/assets/argo_rollouts_install.png new file mode 100644 index 0000000..6e9a100 Binary files /dev/null and b/assets/argo_rollouts_install.png differ diff --git a/assets/argocd_bluegreen1.png b/assets/argocd_bluegreen1.png new file mode 100644 index 0000000..7b5a0dd Binary files /dev/null and b/assets/argocd_bluegreen1.png differ diff --git a/assets/argocd_bluegreen2.png b/assets/argocd_bluegreen2.png new file mode 100644 index 0000000..e603137 Binary files /dev/null and b/assets/argocd_bluegreen2.png differ diff --git a/assets/argocd_bluegreen3.png b/assets/argocd_bluegreen3.png new file mode 100644 index 0000000..db4cecc Binary files /dev/null and b/assets/argocd_bluegreen3.png differ diff --git a/assets/argocd_bluegreen4.png b/assets/argocd_bluegreen4.png new file mode 100644 index 0000000..e3d3d04 Binary files /dev/null and b/assets/argocd_bluegreen4.png differ diff --git a/assets/argocd_bluegreen5.png b/assets/argocd_bluegreen5.png new file mode 100644 index 0000000..71e4670 Binary files /dev/null and b/assets/argocd_bluegreen5.png differ diff --git a/assets/argocd_bluegreen6.png b/assets/argocd_bluegreen6.png new file mode 100644 index 0000000..ba03ef6 Binary files /dev/null and b/assets/argocd_bluegreen6.png differ diff --git a/assets/argocd_bluegreen7.png b/assets/argocd_bluegreen7.png new file mode 100644 index 0000000..3acf8d2 Binary files /dev/null and b/assets/argocd_bluegreen7.png differ diff --git a/assets/argocd_bluegreen8.png b/assets/argocd_bluegreen8.png new file mode 100644 index 0000000..6aae9bb Binary files /dev/null and b/assets/argocd_bluegreen8.png differ diff --git a/assets/argocd_bluegreen_resume.png b/assets/argocd_bluegreen_resume.png new file mode 100644 index 0000000..6b02931 Binary files /dev/null and b/assets/argocd_bluegreen_resume.png differ diff --git a/assets/argocd_bluegreen_resume_action.png b/assets/argocd_bluegreen_resume_action.png new file mode 100644 index 0000000..5a11ee7 Binary files /dev/null and b/assets/argocd_bluegreen_resume_action.png differ diff --git a/assets/argocd_canary1.png b/assets/argocd_canary1.png new file mode 100644 index 0000000..1949919 Binary files /dev/null and b/assets/argocd_canary1.png differ diff --git a/assets/argocd_canary2.png b/assets/argocd_canary2.png new file mode 100644 index 0000000..d194f9f Binary files /dev/null and b/assets/argocd_canary2.png differ diff --git a/assets/argocd_canary3.png b/assets/argocd_canary3.png new file mode 100644 index 0000000..3287fea Binary files /dev/null and b/assets/argocd_canary3.png differ diff --git a/assets/argocd_canary4.png b/assets/argocd_canary4.png new file mode 100644 index 0000000..a8cce2c Binary files /dev/null and b/assets/argocd_canary4.png differ diff --git a/assets/argocd_canary5.png b/assets/argocd_canary5.png new file mode 100644 index 0000000..0b98e20 Binary files /dev/null and b/assets/argocd_canary5.png differ diff --git a/assets/argocd_canary6.png b/assets/argocd_canary6.png new file mode 100644 index 0000000..5631390 Binary files /dev/null and b/assets/argocd_canary6.png differ diff --git a/assets/argocd_canary7.png b/assets/argocd_canary7.png new file mode 100644 index 0000000..6bbf023 Binary files /dev/null and b/assets/argocd_canary7.png differ diff --git a/assets/argocd_edit_svc_after.png b/assets/argocd_edit_svc_after.png new file mode 100644 index 0000000..941e6ee Binary files /dev/null and b/assets/argocd_edit_svc_after.png differ diff --git a/assets/argocd_edit_svc_before.png b/assets/argocd_edit_svc_before.png new file mode 100644 index 0000000..f777ccf Binary files /dev/null and b/assets/argocd_edit_svc_before.png differ diff --git a/assets/argocd_edit_svc_finish.png b/assets/argocd_edit_svc_finish.png new file mode 100644 index 0000000..1ec5e91 Binary files /dev/null and b/assets/argocd_edit_svc_finish.png differ diff --git a/assets/argocd_ingress.png b/assets/argocd_ingress.png new file mode 100644 index 0000000..e1a9337 Binary files /dev/null and b/assets/argocd_ingress.png differ diff --git a/assets/argocd_install1.png b/assets/argocd_install1.png new file mode 100644 index 0000000..ccbf54b Binary files /dev/null and b/assets/argocd_install1.png differ diff --git a/assets/argocd_install2.png b/assets/argocd_install2.png new file mode 100644 index 0000000..d18639d Binary files /dev/null and b/assets/argocd_install2.png differ diff --git a/assets/argocd_install3.png b/assets/argocd_install3.png new file mode 100644 index 0000000..3c2e958 Binary files /dev/null and b/assets/argocd_install3.png differ diff --git a/assets/argocd_install4.png b/assets/argocd_install4.png new file mode 100644 index 0000000..7c19590 Binary files /dev/null and b/assets/argocd_install4.png differ diff --git a/assets/argocd_install5.png b/assets/argocd_install5.png new file mode 100644 index 0000000..9963704 Binary files /dev/null and b/assets/argocd_install5.png differ diff --git a/assets/argocd_mark.png b/assets/argocd_mark.png new file mode 100644 index 0000000..c775df0 Binary files /dev/null and b/assets/argocd_mark.png differ diff --git a/assets/argocd_new_account.png b/assets/argocd_new_account.png new file mode 100644 index 0000000..be8ea32 Binary files /dev/null and b/assets/argocd_new_account.png differ diff --git a/assets/argocd_new_account_role.png b/assets/argocd_new_account_role.png new file mode 100644 index 0000000..9d28216 Binary files /dev/null and b/assets/argocd_new_account_role.png differ diff --git a/assets/argocd_newapp1.png b/assets/argocd_newapp1.png new file mode 100644 index 0000000..481e493 Binary files /dev/null and b/assets/argocd_newapp1.png differ diff --git a/assets/argocd_newapp2.png b/assets/argocd_newapp2.png new file mode 100644 index 0000000..032ca0c Binary files /dev/null and b/assets/argocd_newapp2.png differ diff --git a/assets/argocd_practice1.png b/assets/argocd_practice1.png new file mode 100644 index 0000000..94da6b7 Binary files /dev/null and b/assets/argocd_practice1.png differ diff --git a/assets/argocd_practice10.png b/assets/argocd_practice10.png new file mode 100644 index 0000000..9e9ca52 Binary files /dev/null and b/assets/argocd_practice10.png differ diff --git a/assets/argocd_practice2.png b/assets/argocd_practice2.png new file mode 100644 index 0000000..ef5420e Binary files /dev/null and b/assets/argocd_practice2.png differ diff --git a/assets/argocd_practice3.png b/assets/argocd_practice3.png new file mode 100644 index 0000000..9f6e3ad Binary files /dev/null and b/assets/argocd_practice3.png differ diff --git a/assets/argocd_practice4.png b/assets/argocd_practice4.png new file mode 100644 index 0000000..fef434b Binary files /dev/null and b/assets/argocd_practice4.png differ diff --git a/assets/argocd_practice5.png b/assets/argocd_practice5.png new file mode 100644 index 0000000..d2b76b0 Binary files /dev/null and b/assets/argocd_practice5.png differ diff --git a/assets/argocd_practice6.png b/assets/argocd_practice6.png new file mode 100644 index 0000000..0525d13 Binary files /dev/null and b/assets/argocd_practice6.png differ diff --git a/assets/argocd_practice7.png b/assets/argocd_practice7.png new file mode 100644 index 0000000..531d7ab Binary files /dev/null and b/assets/argocd_practice7.png differ diff --git a/assets/argocd_practice8.png b/assets/argocd_practice8.png new file mode 100644 index 0000000..b1c28a3 Binary files /dev/null and b/assets/argocd_practice8.png differ diff --git a/assets/argocd_practice9.png b/assets/argocd_practice9.png new file mode 100644 index 0000000..fc5ea2d Binary files /dev/null and b/assets/argocd_practice9.png differ diff --git a/assets/argocd_remote_cluster_add.png b/assets/argocd_remote_cluster_add.png new file mode 100644 index 0000000..bb9046e Binary files /dev/null and b/assets/argocd_remote_cluster_add.png differ diff --git a/assets/argocd_swagger.png b/assets/argocd_swagger.png new file mode 100644 index 0000000..941e62b Binary files /dev/null and b/assets/argocd_swagger.png differ diff --git a/assets/argocd_update_password.png b/assets/argocd_update_password.png new file mode 100644 index 0000000..f6b97f3 Binary files /dev/null and b/assets/argocd_update_password.png differ diff --git a/assets/argocd_web_start.png b/assets/argocd_web_start.png new file mode 100644 index 0000000..3d7d818 Binary files /dev/null and b/assets/argocd_web_start.png differ diff --git a/assets/auto_import.png b/assets/auto_import.png new file mode 100644 index 0000000..3f52cde Binary files /dev/null and b/assets/auto_import.png differ diff --git a/assets/blue_green_overview.png b/assets/blue_green_overview.png new file mode 100644 index 0000000..43a9c58 Binary files /dev/null and b/assets/blue_green_overview.png differ diff --git a/assets/build_again.png b/assets/build_again.png new file mode 100644 index 0000000..b95502c Binary files /dev/null and b/assets/build_again.png differ diff --git a/assets/build_console_output.png b/assets/build_console_output.png new file mode 100644 index 0000000..bf9d535 Binary files /dev/null and b/assets/build_console_output.png differ diff --git a/assets/build_docker_access_denied.png b/assets/build_docker_access_denied.png new file mode 100644 index 0000000..705618b Binary files /dev/null and b/assets/build_docker_access_denied.png differ diff --git a/assets/build_dockerhub_check.png b/assets/build_dockerhub_check.png new file mode 100644 index 0000000..d9e5098 Binary files /dev/null and b/assets/build_dockerhub_check.png differ diff --git a/assets/build_error.png b/assets/build_error.png new file mode 100644 index 0000000..7cd10f2 Binary files /dev/null and b/assets/build_error.png differ diff --git a/assets/build_finish.png b/assets/build_finish.png new file mode 100644 index 0000000..547e7a8 Binary files /dev/null and b/assets/build_finish.png differ diff --git a/assets/build_history.png b/assets/build_history.png new file mode 100644 index 0000000..1962735 Binary files /dev/null and b/assets/build_history.png differ diff --git a/assets/build_stage1.png b/assets/build_stage1.png new file mode 100644 index 0000000..9fd68de Binary files /dev/null and b/assets/build_stage1.png differ diff --git a/assets/build_stage2.png b/assets/build_stage2.png new file mode 100644 index 0000000..c3f6b1a Binary files /dev/null and b/assets/build_stage2.png differ diff --git a/assets/canary_config.png b/assets/canary_config.png new file mode 100644 index 0000000..83f7170 Binary files /dev/null and b/assets/canary_config.png differ diff --git a/assets/canary_overview.png b/assets/canary_overview.png new file mode 100644 index 0000000..b8d60b8 Binary files /dev/null and b/assets/canary_overview.png differ diff --git a/assets/cat_k3s_yaml.png b/assets/cat_k3s_yaml.png new file mode 100644 index 0000000..56f9c02 Binary files /dev/null and b/assets/cat_k3s_yaml.png differ diff --git a/assets/chapter2-2-answer.png b/assets/chapter2-2-answer.png new file mode 100644 index 0000000..9b1c31a Binary files /dev/null and b/assets/chapter2-2-answer.png differ diff --git a/assets/chapter2-2-answer2.png b/assets/chapter2-2-answer2.png new file mode 100644 index 0000000..4d7afc5 Binary files /dev/null and b/assets/chapter2-2-answer2.png differ diff --git a/assets/chrome_extension_pin.png b/assets/chrome_extension_pin.png new file mode 100644 index 0000000..c17d6a9 Binary files /dev/null and b/assets/chrome_extension_pin.png differ diff --git a/assets/chrome_extensions.png b/assets/chrome_extensions.png new file mode 100644 index 0000000..c5cb95a Binary files /dev/null and b/assets/chrome_extensions.png differ diff --git a/assets/cluster_info.png b/assets/cluster_info.png new file mode 100644 index 0000000..a5d7669 Binary files /dev/null and b/assets/cluster_info.png differ diff --git a/assets/config_merge.png b/assets/config_merge.png new file mode 100644 index 0000000..c1a131e Binary files /dev/null and b/assets/config_merge.png differ diff --git a/assets/configure_global_security.png b/assets/configure_global_security.png new file mode 100644 index 0000000..2b4f6b3 Binary files /dev/null and b/assets/configure_global_security.png differ diff --git a/assets/configure_global_security2.png b/assets/configure_global_security2.png new file mode 100644 index 0000000..fe51636 Binary files /dev/null and b/assets/configure_global_security2.png differ diff --git a/assets/container_portal.png b/assets/container_portal.png new file mode 100644 index 0000000..22ed4b7 Binary files /dev/null and b/assets/container_portal.png differ diff --git a/assets/container_portal1.png b/assets/container_portal1.png new file mode 100644 index 0000000..d729210 Binary files /dev/null and b/assets/container_portal1.png differ diff --git a/assets/crud1.png b/assets/crud1.png new file mode 100644 index 0000000..894e433 Binary files /dev/null and b/assets/crud1.png differ diff --git a/assets/crud2.png b/assets/crud2.png new file mode 100644 index 0000000..1c74a67 Binary files /dev/null and b/assets/crud2.png differ diff --git a/assets/crud3.png b/assets/crud3.png new file mode 100644 index 0000000..1ddc417 Binary files /dev/null and b/assets/crud3.png differ diff --git a/assets/datadog_apikey_find1.png b/assets/datadog_apikey_find1.png new file mode 100644 index 0000000..6de0712 Binary files /dev/null and b/assets/datadog_apikey_find1.png differ diff --git a/assets/datadog_apikey_find2.png b/assets/datadog_apikey_find2.png new file mode 100644 index 0000000..6a1ed86 Binary files /dev/null and b/assets/datadog_apikey_find2.png differ diff --git a/assets/datadog_apikey_find3.png b/assets/datadog_apikey_find3.png new file mode 100644 index 0000000..a8ab7b6 Binary files /dev/null and b/assets/datadog_apikey_find3.png differ diff --git a/assets/datadog_apikey_find4.png b/assets/datadog_apikey_find4.png new file mode 100644 index 0000000..b9fed2e Binary files /dev/null and b/assets/datadog_apikey_find4.png differ diff --git a/assets/datadog_apm_trace.png b/assets/datadog_apm_trace.png new file mode 100644 index 0000000..f54067c Binary files /dev/null and b/assets/datadog_apm_trace.png differ diff --git a/assets/datadog_apm_trace1.png b/assets/datadog_apm_trace1.png new file mode 100644 index 0000000..2bd0dfa Binary files /dev/null and b/assets/datadog_apm_trace1.png differ diff --git a/assets/datadog_apm_trace2.png b/assets/datadog_apm_trace2.png new file mode 100644 index 0000000..c7dbd2b Binary files /dev/null and b/assets/datadog_apm_trace2.png differ diff --git a/assets/datadog_appkey1.png b/assets/datadog_appkey1.png new file mode 100644 index 0000000..62a0816 Binary files /dev/null and b/assets/datadog_appkey1.png differ diff --git a/assets/datadog_appkey2.png b/assets/datadog_appkey2.png new file mode 100644 index 0000000..317e105 Binary files /dev/null and b/assets/datadog_appkey2.png differ diff --git a/assets/datadog_appkey3.png b/assets/datadog_appkey3.png new file mode 100644 index 0000000..347012a Binary files /dev/null and b/assets/datadog_appkey3.png differ diff --git a/assets/datadog_container_trace.png b/assets/datadog_container_trace.png new file mode 100644 index 0000000..4b25a61 Binary files /dev/null and b/assets/datadog_container_trace.png differ diff --git a/assets/datadog_docs1.png b/assets/datadog_docs1.png new file mode 100644 index 0000000..f31b129 Binary files /dev/null and b/assets/datadog_docs1.png differ diff --git a/assets/datadog_docs2.png b/assets/datadog_docs2.png new file mode 100644 index 0000000..df3d850 Binary files /dev/null and b/assets/datadog_docs2.png differ diff --git a/assets/datadog_docs3.png b/assets/datadog_docs3.png new file mode 100644 index 0000000..61cf89a Binary files /dev/null and b/assets/datadog_docs3.png differ diff --git a/assets/datadog_dogstatsd.png b/assets/datadog_dogstatsd.png new file mode 100644 index 0000000..fba2c84 Binary files /dev/null and b/assets/datadog_dogstatsd.png differ diff --git a/assets/datadog_home.png b/assets/datadog_home.png new file mode 100644 index 0000000..3b579a5 Binary files /dev/null and b/assets/datadog_home.png differ diff --git a/assets/datadog_infra_list.png b/assets/datadog_infra_list.png new file mode 100644 index 0000000..4676fcf Binary files /dev/null and b/assets/datadog_infra_list.png differ diff --git a/assets/datadog_infra_server.png b/assets/datadog_infra_server.png new file mode 100644 index 0000000..6f83074 Binary files /dev/null and b/assets/datadog_infra_server.png differ diff --git a/assets/datadog_infra_server_container.png b/assets/datadog_infra_server_container.png new file mode 100644 index 0000000..9d242a0 Binary files /dev/null and b/assets/datadog_infra_server_container.png differ diff --git a/assets/datadog_infra_server_detail.png b/assets/datadog_infra_server_detail.png new file mode 100644 index 0000000..88223ec Binary files /dev/null and b/assets/datadog_infra_server_detail.png differ diff --git a/assets/datadog_infra_trace.png b/assets/datadog_infra_trace.png new file mode 100644 index 0000000..e34d8ca Binary files /dev/null and b/assets/datadog_infra_trace.png differ diff --git a/assets/datadog_k8s_container.png b/assets/datadog_k8s_container.png new file mode 100644 index 0000000..0f438c4 Binary files /dev/null and b/assets/datadog_k8s_container.png differ diff --git a/assets/datadog_k8s_container_prev.png b/assets/datadog_k8s_container_prev.png new file mode 100644 index 0000000..d31fe9e Binary files /dev/null and b/assets/datadog_k8s_container_prev.png differ diff --git a/assets/datadog_select_zone.png b/assets/datadog_select_zone.png new file mode 100644 index 0000000..2a1fe87 Binary files /dev/null and b/assets/datadog_select_zone.png differ diff --git a/assets/datadog_signup.png b/assets/datadog_signup.png new file mode 100644 index 0000000..132a82a Binary files /dev/null and b/assets/datadog_signup.png differ diff --git a/assets/datadog_trace_collect.png b/assets/datadog_trace_collect.png new file mode 100644 index 0000000..734094b Binary files /dev/null and b/assets/datadog_trace_collect.png differ diff --git a/assets/datadog_trace_error.png b/assets/datadog_trace_error.png new file mode 100644 index 0000000..acb2def Binary files /dev/null and b/assets/datadog_trace_error.png differ diff --git a/assets/datadog_trace_vm1.png b/assets/datadog_trace_vm1.png new file mode 100644 index 0000000..ffb10ff Binary files /dev/null and b/assets/datadog_trace_vm1.png differ diff --git a/assets/datadog_upgrade.png b/assets/datadog_upgrade.png new file mode 100644 index 0000000..39927b0 Binary files /dev/null and b/assets/datadog_upgrade.png differ diff --git a/assets/datagog_k8s_architecture.png b/assets/datagog_k8s_architecture.png new file mode 100644 index 0000000..e819496 Binary files /dev/null and b/assets/datagog_k8s_architecture.png differ diff --git a/assets/db_summary.png b/assets/db_summary.png new file mode 100644 index 0000000..1c6594d Binary files /dev/null and b/assets/db_summary.png differ diff --git a/assets/default_branch_modify.png b/assets/default_branch_modify.png new file mode 100644 index 0000000..c1187a1 Binary files /dev/null and b/assets/default_branch_modify.png differ diff --git a/assets/delete1.png b/assets/delete1.png new file mode 100644 index 0000000..f0bde82 Binary files /dev/null and b/assets/delete1.png differ diff --git a/assets/delete2-1.png b/assets/delete2-1.png new file mode 100644 index 0000000..ee84cca Binary files /dev/null and b/assets/delete2-1.png differ diff --git a/assets/delete2.png b/assets/delete2.png new file mode 100644 index 0000000..72c1596 Binary files /dev/null and b/assets/delete2.png differ diff --git a/assets/delete3.png b/assets/delete3.png new file mode 100644 index 0000000..8f43d03 Binary files /dev/null and b/assets/delete3.png differ diff --git a/assets/delete4.png b/assets/delete4.png new file mode 100644 index 0000000..42eee0b Binary files /dev/null and b/assets/delete4.png differ diff --git a/assets/delete5.png b/assets/delete5.png new file mode 100644 index 0000000..c6a4f76 Binary files /dev/null and b/assets/delete5.png differ diff --git a/assets/demo_replica.png b/assets/demo_replica.png new file mode 100644 index 0000000..1d178ed Binary files /dev/null and b/assets/demo_replica.png differ diff --git a/assets/demo_replica2.png b/assets/demo_replica2.png new file mode 100644 index 0000000..77d7ab8 Binary files /dev/null and b/assets/demo_replica2.png differ diff --git a/assets/deployment.png b/assets/deployment.png new file mode 100644 index 0000000..2ac9f9e Binary files /dev/null and b/assets/deployment.png differ diff --git a/assets/disk_add1.png b/assets/disk_add1.png new file mode 100644 index 0000000..a7f2460 Binary files /dev/null and b/assets/disk_add1.png differ diff --git a/assets/disk_add2.png b/assets/disk_add2.png new file mode 100644 index 0000000..deb081d Binary files /dev/null and b/assets/disk_add2.png differ diff --git a/assets/disk_add3.png b/assets/disk_add3.png new file mode 100644 index 0000000..27645b0 Binary files /dev/null and b/assets/disk_add3.png differ diff --git a/assets/disk_add4.png b/assets/disk_add4.png new file mode 100644 index 0000000..a443591 Binary files /dev/null and b/assets/disk_add4.png differ diff --git a/assets/disk_add5.png b/assets/disk_add5.png new file mode 100644 index 0000000..1bc3c54 Binary files /dev/null and b/assets/disk_add5.png differ diff --git a/assets/disk_add6.png b/assets/disk_add6.png new file mode 100644 index 0000000..df58ee5 Binary files /dev/null and b/assets/disk_add6.png differ diff --git a/assets/disk_add7.png b/assets/disk_add7.png new file mode 100644 index 0000000..9182ce3 Binary files /dev/null and b/assets/disk_add7.png differ diff --git a/assets/disk_add_fdisk.png b/assets/disk_add_fdisk.png new file mode 100644 index 0000000..8f48ca4 Binary files /dev/null and b/assets/disk_add_fdisk.png differ diff --git a/assets/disk_mount.png b/assets/disk_mount.png new file mode 100644 index 0000000..f1407b1 Binary files /dev/null and b/assets/disk_mount.png differ diff --git a/assets/docker_build_t1.png b/assets/docker_build_t1.png new file mode 100644 index 0000000..9092b1f Binary files /dev/null and b/assets/docker_build_t1.png differ diff --git a/assets/docker_build_t2.png b/assets/docker_build_t2.png new file mode 100644 index 0000000..38c3e70 Binary files /dev/null and b/assets/docker_build_t2.png differ diff --git a/assets/docker_commit.png b/assets/docker_commit.png new file mode 100644 index 0000000..d964d61 Binary files /dev/null and b/assets/docker_commit.png differ diff --git a/assets/docker_compose_install.png b/assets/docker_compose_install.png new file mode 100644 index 0000000..1609461 Binary files /dev/null and b/assets/docker_compose_install.png differ diff --git a/assets/docker_compose_ls.png b/assets/docker_compose_ls.png new file mode 100644 index 0000000..30140dc Binary files /dev/null and b/assets/docker_compose_ls.png differ diff --git a/assets/docker_compose_mkdir.png b/assets/docker_compose_mkdir.png new file mode 100644 index 0000000..1b1d156 Binary files /dev/null and b/assets/docker_compose_mkdir.png differ diff --git a/assets/docker_compose_ps.png b/assets/docker_compose_ps.png new file mode 100644 index 0000000..1f58cc8 Binary files /dev/null and b/assets/docker_compose_ps.png differ diff --git a/assets/docker_compose_up.png b/assets/docker_compose_up.png new file mode 100644 index 0000000..cd6c14f Binary files /dev/null and b/assets/docker_compose_up.png differ diff --git a/assets/docker_compose_version.png b/assets/docker_compose_version.png new file mode 100644 index 0000000..c27db5e Binary files /dev/null and b/assets/docker_compose_version.png differ diff --git a/assets/docker_compose_volume.png b/assets/docker_compose_volume.png new file mode 100644 index 0000000..c70b4d9 Binary files /dev/null and b/assets/docker_compose_volume.png differ diff --git a/assets/docker_compose_web.png b/assets/docker_compose_web.png new file mode 100644 index 0000000..c51b31e Binary files /dev/null and b/assets/docker_compose_web.png differ diff --git a/assets/docker_denied.png b/assets/docker_denied.png new file mode 100644 index 0000000..b1a7494 Binary files /dev/null and b/assets/docker_denied.png differ diff --git a/assets/docker_edu2_push.png b/assets/docker_edu2_push.png new file mode 100644 index 0000000..a40f0d0 Binary files /dev/null and b/assets/docker_edu2_push.png differ diff --git a/assets/docker_exec.png b/assets/docker_exec.png new file mode 100644 index 0000000..abbe181 Binary files /dev/null and b/assets/docker_exec.png differ diff --git a/assets/docker_hub_make_public.png b/assets/docker_hub_make_public.png new file mode 100644 index 0000000..04f100d Binary files /dev/null and b/assets/docker_hub_make_public.png differ diff --git a/assets/docker_hub_world.png b/assets/docker_hub_world.png new file mode 100644 index 0000000..6b600de Binary files /dev/null and b/assets/docker_hub_world.png differ diff --git a/assets/docker_images.png b/assets/docker_images.png new file mode 100644 index 0000000..cdb79bb Binary files /dev/null and b/assets/docker_images.png differ diff --git a/assets/docker_logs.png b/assets/docker_logs.png new file mode 100644 index 0000000..93ec2ad Binary files /dev/null and b/assets/docker_logs.png differ diff --git a/assets/docker_overview.png b/assets/docker_overview.png new file mode 100644 index 0000000..355aba3 Binary files /dev/null and b/assets/docker_overview.png differ diff --git a/assets/docker_ps.png b/assets/docker_ps.png new file mode 100644 index 0000000..b9404df Binary files /dev/null and b/assets/docker_ps.png differ diff --git a/assets/docker_ps_stop.png b/assets/docker_ps_stop.png new file mode 100644 index 0000000..5c1fc1f Binary files /dev/null and b/assets/docker_ps_stop.png differ diff --git a/assets/docker_pull_edu1.png b/assets/docker_pull_edu1.png new file mode 100644 index 0000000..4765c43 Binary files /dev/null and b/assets/docker_pull_edu1.png differ diff --git a/assets/docker_push.png b/assets/docker_push.png new file mode 100644 index 0000000..b914b42 Binary files /dev/null and b/assets/docker_push.png differ diff --git a/assets/docker_root_dir.png b/assets/docker_root_dir.png new file mode 100644 index 0000000..0b9173b Binary files /dev/null and b/assets/docker_root_dir.png differ diff --git a/assets/docker_run_d.png b/assets/docker_run_d.png new file mode 100644 index 0000000..1927f99 Binary files /dev/null and b/assets/docker_run_d.png differ diff --git a/assets/docker_run_edu1.png b/assets/docker_run_edu1.png new file mode 100644 index 0000000..860799b Binary files /dev/null and b/assets/docker_run_edu1.png differ diff --git a/assets/docker_run_world.png b/assets/docker_run_world.png new file mode 100644 index 0000000..056eb80 Binary files /dev/null and b/assets/docker_run_world.png differ diff --git a/assets/docker_stats.png b/assets/docker_stats.png new file mode 100644 index 0000000..2e72c60 Binary files /dev/null and b/assets/docker_stats.png differ diff --git a/assets/docker_system_df_v.png b/assets/docker_system_df_v.png new file mode 100644 index 0000000..e83a9e4 Binary files /dev/null and b/assets/docker_system_df_v.png differ diff --git a/assets/docker_version.png b/assets/docker_version.png new file mode 100644 index 0000000..3d8b9ab Binary files /dev/null and b/assets/docker_version.png differ diff --git a/assets/dockerhub_edu2_image.png b/assets/dockerhub_edu2_image.png new file mode 100644 index 0000000..1df92ee Binary files /dev/null and b/assets/dockerhub_edu2_image.png differ diff --git a/assets/downward_api_pod.png b/assets/downward_api_pod.png new file mode 100644 index 0000000..ccb177e Binary files /dev/null and b/assets/downward_api_pod.png differ diff --git a/assets/dto_package_create.png b/assets/dto_package_create.png new file mode 100644 index 0000000..23ed269 Binary files /dev/null and b/assets/dto_package_create.png differ diff --git a/assets/du_h_overlay.png b/assets/du_h_overlay.png new file mode 100644 index 0000000..fa8855a Binary files /dev/null and b/assets/du_h_overlay.png differ diff --git a/assets/file_encoding.png b/assets/file_encoding.png new file mode 100644 index 0000000..02cdd1a Binary files /dev/null and b/assets/file_encoding.png differ diff --git a/assets/first_login1.png b/assets/first_login1.png new file mode 100644 index 0000000..849f17f Binary files /dev/null and b/assets/first_login1.png differ diff --git a/assets/first_login2.png b/assets/first_login2.png new file mode 100644 index 0000000..0e59e80 Binary files /dev/null and b/assets/first_login2.png differ diff --git a/assets/flask_web_edu1.png b/assets/flask_web_edu1.png new file mode 100644 index 0000000..ca975ec Binary files /dev/null and b/assets/flask_web_edu1.png differ diff --git a/assets/git_clone.png b/assets/git_clone.png new file mode 100644 index 0000000..d72767c Binary files /dev/null and b/assets/git_clone.png differ diff --git a/assets/git_push.png b/assets/git_push.png new file mode 100644 index 0000000..290329e Binary files /dev/null and b/assets/git_push.png differ diff --git a/assets/git_push_github.png b/assets/git_push_github.png new file mode 100644 index 0000000..6fe6146 Binary files /dev/null and b/assets/git_push_github.png differ diff --git a/assets/git_remote.png b/assets/git_remote.png new file mode 100644 index 0000000..81149e2 Binary files /dev/null and b/assets/git_remote.png differ diff --git a/assets/git_remote_modify.png b/assets/git_remote_modify.png new file mode 100644 index 0000000..a889697 Binary files /dev/null and b/assets/git_remote_modify.png differ diff --git a/assets/git_version.png b/assets/git_version.png new file mode 100644 index 0000000..d28b848 Binary files /dev/null and b/assets/git_version.png differ diff --git a/assets/github_action1.png b/assets/github_action1.png new file mode 100644 index 0000000..171d9dd Binary files /dev/null and b/assets/github_action1.png differ diff --git a/assets/github_action10.png b/assets/github_action10.png new file mode 100644 index 0000000..6fd02e2 Binary files /dev/null and b/assets/github_action10.png differ diff --git a/assets/github_action11.png b/assets/github_action11.png new file mode 100644 index 0000000..76322c0 Binary files /dev/null and b/assets/github_action11.png differ diff --git a/assets/github_action12.png b/assets/github_action12.png new file mode 100644 index 0000000..ff1851b Binary files /dev/null and b/assets/github_action12.png differ diff --git a/assets/github_action13.png b/assets/github_action13.png new file mode 100644 index 0000000..8e20b8e Binary files /dev/null and b/assets/github_action13.png differ diff --git a/assets/github_action14.png b/assets/github_action14.png new file mode 100644 index 0000000..c199dee Binary files /dev/null and b/assets/github_action14.png differ diff --git a/assets/github_action15.png b/assets/github_action15.png new file mode 100644 index 0000000..60ea4c3 Binary files /dev/null and b/assets/github_action15.png differ diff --git a/assets/github_action3.png b/assets/github_action3.png new file mode 100644 index 0000000..5099779 Binary files /dev/null and b/assets/github_action3.png differ diff --git a/assets/github_action4.png b/assets/github_action4.png new file mode 100644 index 0000000..d15babd Binary files /dev/null and b/assets/github_action4.png differ diff --git a/assets/github_action5.png b/assets/github_action5.png new file mode 100644 index 0000000..7ef7676 Binary files /dev/null and b/assets/github_action5.png differ diff --git a/assets/github_action6.png b/assets/github_action6.png new file mode 100644 index 0000000..8d1095e Binary files /dev/null and b/assets/github_action6.png differ diff --git a/assets/github_action7.png b/assets/github_action7.png new file mode 100644 index 0000000..1aa141e Binary files /dev/null and b/assets/github_action7.png differ diff --git a/assets/github_action8-1.png b/assets/github_action8-1.png new file mode 100644 index 0000000..6190171 Binary files /dev/null and b/assets/github_action8-1.png differ diff --git a/assets/github_action8.png b/assets/github_action8.png new file mode 100644 index 0000000..05aae0d Binary files /dev/null and b/assets/github_action8.png differ diff --git a/assets/github_action9.png b/assets/github_action9.png new file mode 100644 index 0000000..d9a45ad Binary files /dev/null and b/assets/github_action9.png differ diff --git a/assets/github_action_docker1.png b/assets/github_action_docker1.png new file mode 100644 index 0000000..74d82f2 Binary files /dev/null and b/assets/github_action_docker1.png differ diff --git a/assets/github_action_docker10.png b/assets/github_action_docker10.png new file mode 100644 index 0000000..3078619 Binary files /dev/null and b/assets/github_action_docker10.png differ diff --git a/assets/github_action_docker2.png b/assets/github_action_docker2.png new file mode 100644 index 0000000..2d687d8 Binary files /dev/null and b/assets/github_action_docker2.png differ diff --git a/assets/github_action_docker3.png b/assets/github_action_docker3.png new file mode 100644 index 0000000..a6c636e Binary files /dev/null and b/assets/github_action_docker3.png differ diff --git a/assets/github_action_docker4.png b/assets/github_action_docker4.png new file mode 100644 index 0000000..af109d8 Binary files /dev/null and b/assets/github_action_docker4.png differ diff --git a/assets/github_action_docker5.png b/assets/github_action_docker5.png new file mode 100644 index 0000000..f582d4b Binary files /dev/null and b/assets/github_action_docker5.png differ diff --git a/assets/github_action_docker6.png b/assets/github_action_docker6.png new file mode 100644 index 0000000..136e935 Binary files /dev/null and b/assets/github_action_docker6.png differ diff --git a/assets/github_action_docker7.png b/assets/github_action_docker7.png new file mode 100644 index 0000000..441232a Binary files /dev/null and b/assets/github_action_docker7.png differ diff --git a/assets/github_action_docker8.png b/assets/github_action_docker8.png new file mode 100644 index 0000000..500ec34 Binary files /dev/null and b/assets/github_action_docker8.png differ diff --git a/assets/github_action_docker9.png b/assets/github_action_docker9.png new file mode 100644 index 0000000..7e8032c Binary files /dev/null and b/assets/github_action_docker9.png differ diff --git a/assets/github_action_manual.png b/assets/github_action_manual.png new file mode 100644 index 0000000..8c7273b Binary files /dev/null and b/assets/github_action_manual.png differ diff --git a/assets/github_action_template.png b/assets/github_action_template.png new file mode 100644 index 0000000..dd38448 Binary files /dev/null and b/assets/github_action_template.png differ diff --git a/assets/github_clone.png b/assets/github_clone.png new file mode 100644 index 0000000..941d7a4 Binary files /dev/null and b/assets/github_clone.png differ diff --git a/assets/github_edu2.png b/assets/github_edu2.png new file mode 100644 index 0000000..43327b9 Binary files /dev/null and b/assets/github_edu2.png differ diff --git a/assets/github_package.png b/assets/github_package.png new file mode 100644 index 0000000..17256d7 Binary files /dev/null and b/assets/github_package.png differ diff --git a/assets/github_tag1.png b/assets/github_tag1.png new file mode 100644 index 0000000..27a4a4d Binary files /dev/null and b/assets/github_tag1.png differ diff --git a/assets/github_tag2.png b/assets/github_tag2.png new file mode 100644 index 0000000..2cc8b94 Binary files /dev/null and b/assets/github_tag2.png differ diff --git a/assets/github_tag3.png b/assets/github_tag3.png new file mode 100644 index 0000000..97fc623 Binary files /dev/null and b/assets/github_tag3.png differ diff --git a/assets/github_tag4.png b/assets/github_tag4.png new file mode 100644 index 0000000..d651c51 Binary files /dev/null and b/assets/github_tag4.png differ diff --git a/assets/github_tag5.png b/assets/github_tag5.png new file mode 100644 index 0000000..901b21c Binary files /dev/null and b/assets/github_tag5.png differ diff --git a/assets/github_tag6.png b/assets/github_tag6.png new file mode 100644 index 0000000..c82332d Binary files /dev/null and b/assets/github_tag6.png differ diff --git a/assets/github_token_setting1.png b/assets/github_token_setting1.png new file mode 100644 index 0000000..4136f2a Binary files /dev/null and b/assets/github_token_setting1.png differ diff --git a/assets/github_token_setting2.png b/assets/github_token_setting2.png new file mode 100644 index 0000000..ce37cd4 Binary files /dev/null and b/assets/github_token_setting2.png differ diff --git a/assets/github_token_setting3.png b/assets/github_token_setting3.png new file mode 100644 index 0000000..3a63aa0 Binary files /dev/null and b/assets/github_token_setting3.png differ diff --git a/assets/github_web_hook.png b/assets/github_web_hook.png new file mode 100644 index 0000000..4ababac Binary files /dev/null and b/assets/github_web_hook.png differ diff --git a/assets/gitops_overview.png b/assets/gitops_overview.png new file mode 100644 index 0000000..0a89163 Binary files /dev/null and b/assets/gitops_overview.png differ diff --git a/assets/gitops_pipeline.png b/assets/gitops_pipeline.png new file mode 100644 index 0000000..36400c2 Binary files /dev/null and b/assets/gitops_pipeline.png differ diff --git a/assets/gitops_pull.png b/assets/gitops_pull.png new file mode 100644 index 0000000..20b750f Binary files /dev/null and b/assets/gitops_pull.png differ diff --git a/assets/gitops_push.png b/assets/gitops_push.png new file mode 100644 index 0000000..9cc04b4 Binary files /dev/null and b/assets/gitops_push.png differ diff --git a/assets/h2db_auto_insert.png b/assets/h2db_auto_insert.png new file mode 100644 index 0000000..efdf744 Binary files /dev/null and b/assets/h2db_auto_insert.png differ diff --git a/assets/helm_install.png b/assets/helm_install.png new file mode 100644 index 0000000..6479932 Binary files /dev/null and b/assets/helm_install.png differ diff --git a/assets/helm_prometheus_install.png b/assets/helm_prometheus_install.png new file mode 100644 index 0000000..2e51ccd Binary files /dev/null and b/assets/helm_prometheus_install.png differ diff --git a/assets/helm_repo_add.png b/assets/helm_repo_add.png new file mode 100644 index 0000000..d3af07b Binary files /dev/null and b/assets/helm_repo_add.png differ diff --git a/assets/helm_search_prometheus.png b/assets/helm_search_prometheus.png new file mode 100644 index 0000000..fb6eb02 Binary files /dev/null and b/assets/helm_search_prometheus.png differ diff --git a/assets/helm_version.png b/assets/helm_version.png new file mode 100644 index 0000000..1064d4a Binary files /dev/null and b/assets/helm_version.png differ diff --git a/assets/hibernate1.png b/assets/hibernate1.png new file mode 100644 index 0000000..6f1ea36 Binary files /dev/null and b/assets/hibernate1.png differ diff --git a/assets/ingress.png b/assets/ingress.png new file mode 100644 index 0000000..8df7820 Binary files /dev/null and b/assets/ingress.png differ diff --git a/assets/ingress_nginx.png b/assets/ingress_nginx.png new file mode 100644 index 0000000..36fabb3 Binary files /dev/null and b/assets/ingress_nginx.png differ diff --git a/assets/inspekt_deploy.png b/assets/inspekt_deploy.png new file mode 100644 index 0000000..40e3676 Binary files /dev/null and b/assets/inspekt_deploy.png differ diff --git a/assets/inspekt_traefik_ingress.png b/assets/inspekt_traefik_ingress.png new file mode 100644 index 0000000..3ec619f Binary files /dev/null and b/assets/inspekt_traefik_ingress.png differ diff --git a/assets/install_k3s.png b/assets/install_k3s.png new file mode 100644 index 0000000..98f5149 Binary files /dev/null and b/assets/install_k3s.png differ diff --git a/assets/intellij_download_mac.png b/assets/intellij_download_mac.png new file mode 100644 index 0000000..5c6ee1c Binary files /dev/null and b/assets/intellij_download_mac.png differ diff --git a/assets/intellij_welcome.png b/assets/intellij_welcome.png new file mode 100644 index 0000000..2e423fc Binary files /dev/null and b/assets/intellij_welcome.png differ diff --git a/assets/istio.png b/assets/istio.png new file mode 100644 index 0000000..d7790f9 Binary files /dev/null and b/assets/istio.png differ diff --git a/assets/java17_mac1.png b/assets/java17_mac1.png new file mode 100644 index 0000000..1e8473f Binary files /dev/null and b/assets/java17_mac1.png differ diff --git a/assets/java17_windows1.png b/assets/java17_windows1.png new file mode 100644 index 0000000..259833a Binary files /dev/null and b/assets/java17_windows1.png differ diff --git a/assets/jdbc1.png b/assets/jdbc1.png new file mode 100644 index 0000000..5bcb778 Binary files /dev/null and b/assets/jdbc1.png differ diff --git a/assets/jenkins_admin_password.png b/assets/jenkins_admin_password.png new file mode 100644 index 0000000..579f29a Binary files /dev/null and b/assets/jenkins_admin_password.png differ diff --git a/assets/jenkins_admin_user.png b/assets/jenkins_admin_user.png new file mode 100644 index 0000000..24114c7 Binary files /dev/null and b/assets/jenkins_admin_user.png differ diff --git a/assets/jenkins_admin_user_create.png b/assets/jenkins_admin_user_create.png new file mode 100644 index 0000000..2578b95 Binary files /dev/null and b/assets/jenkins_admin_user_create.png differ diff --git a/assets/jenkins_admin_user_created.png b/assets/jenkins_admin_user_created.png new file mode 100644 index 0000000..771d667 Binary files /dev/null and b/assets/jenkins_admin_user_created.png differ diff --git a/assets/jenkins_build_folder.png b/assets/jenkins_build_folder.png new file mode 100644 index 0000000..09e9043 Binary files /dev/null and b/assets/jenkins_build_folder.png differ diff --git a/assets/jenkins_build_history.png b/assets/jenkins_build_history.png new file mode 100644 index 0000000..909f0c0 Binary files /dev/null and b/assets/jenkins_build_history.png differ diff --git a/assets/jenkins_ci_start.png b/assets/jenkins_ci_start.png new file mode 100644 index 0000000..c0bcdd9 Binary files /dev/null and b/assets/jenkins_ci_start.png differ diff --git a/assets/jenkins_current_variable.png b/assets/jenkins_current_variable.png new file mode 100644 index 0000000..5a42cb1 Binary files /dev/null and b/assets/jenkins_current_variable.png differ diff --git a/assets/jenkins_dockerhub_credential.png b/assets/jenkins_dockerhub_credential.png new file mode 100644 index 0000000..14b895c Binary files /dev/null and b/assets/jenkins_dockerhub_credential.png differ diff --git a/assets/jenkins_env_variable.png b/assets/jenkins_env_variable.png new file mode 100644 index 0000000..e53227c Binary files /dev/null and b/assets/jenkins_env_variable.png differ diff --git a/assets/jenkins_first_build.png b/assets/jenkins_first_build.png new file mode 100644 index 0000000..eac31eb Binary files /dev/null and b/assets/jenkins_first_build.png differ diff --git a/assets/jenkins_first_manage_plugins.png b/assets/jenkins_first_manage_plugins.png new file mode 100644 index 0000000..b420cdc Binary files /dev/null and b/assets/jenkins_first_manage_plugins.png differ diff --git a/assets/jenkins_github_credential1.png b/assets/jenkins_github_credential1.png new file mode 100644 index 0000000..4970ff0 Binary files /dev/null and b/assets/jenkins_github_credential1.png differ diff --git a/assets/jenkins_github_credential2.png b/assets/jenkins_github_credential2.png new file mode 100644 index 0000000..79f5ddc Binary files /dev/null and b/assets/jenkins_github_credential2.png differ diff --git a/assets/jenkins_github_credential3.png b/assets/jenkins_github_credential3.png new file mode 100644 index 0000000..2f1da59 Binary files /dev/null and b/assets/jenkins_github_credential3.png differ diff --git a/assets/jenkins_github_credential4.png b/assets/jenkins_github_credential4.png new file mode 100644 index 0000000..1e0dba2 Binary files /dev/null and b/assets/jenkins_github_credential4.png differ diff --git a/assets/jenkins_github_dockerhub_credential.png b/assets/jenkins_github_dockerhub_credential.png new file mode 100644 index 0000000..e117e01 Binary files /dev/null and b/assets/jenkins_github_dockerhub_credential.png differ diff --git a/assets/jenkins_home_folder.png b/assets/jenkins_home_folder.png new file mode 100644 index 0000000..5c498f0 Binary files /dev/null and b/assets/jenkins_home_folder.png differ diff --git a/assets/jenkins_is_ready.png b/assets/jenkins_is_ready.png new file mode 100644 index 0000000..53aec90 Binary files /dev/null and b/assets/jenkins_is_ready.png differ diff --git a/assets/jenkins_plugin_install.png b/assets/jenkins_plugin_install.png new file mode 100644 index 0000000..ae314b1 Binary files /dev/null and b/assets/jenkins_plugin_install.png differ diff --git a/assets/jenkins_restart_check.png b/assets/jenkins_restart_check.png new file mode 100644 index 0000000..700c2b2 Binary files /dev/null and b/assets/jenkins_restart_check.png differ diff --git a/assets/jenkins_restarting.png b/assets/jenkins_restarting.png new file mode 100644 index 0000000..551267b Binary files /dev/null and b/assets/jenkins_restarting.png differ diff --git a/assets/jenkins_stage_view.png b/assets/jenkins_stage_view.png new file mode 100644 index 0000000..ecf2811 Binary files /dev/null and b/assets/jenkins_stage_view.png differ diff --git a/assets/jenkins_status.png b/assets/jenkins_status.png new file mode 100644 index 0000000..357239c Binary files /dev/null and b/assets/jenkins_status.png differ diff --git a/assets/jenkins_suggested_plugin.png b/assets/jenkins_suggested_plugin.png new file mode 100644 index 0000000..91277ea Binary files /dev/null and b/assets/jenkins_suggested_plugin.png differ diff --git a/assets/jenkins_suggested_plugin2.png b/assets/jenkins_suggested_plugin2.png new file mode 100644 index 0000000..bacd40b Binary files /dev/null and b/assets/jenkins_suggested_plugin2.png differ diff --git a/assets/jenkins_tag.png b/assets/jenkins_tag.png new file mode 100644 index 0000000..7859a50 Binary files /dev/null and b/assets/jenkins_tag.png differ diff --git a/assets/jenkins_tag_build.png b/assets/jenkins_tag_build.png new file mode 100644 index 0000000..4c06153 Binary files /dev/null and b/assets/jenkins_tag_build.png differ diff --git a/assets/jenkins_user.png b/assets/jenkins_user.png new file mode 100644 index 0000000..257cfc1 Binary files /dev/null and b/assets/jenkins_user.png differ diff --git a/assets/jpa_compare_1.png b/assets/jpa_compare_1.png new file mode 100644 index 0000000..111ef31 Binary files /dev/null and b/assets/jpa_compare_1.png differ diff --git a/assets/json_format.png b/assets/json_format.png new file mode 100644 index 0000000..215f041 Binary files /dev/null and b/assets/json_format.png differ diff --git a/assets/k3s_cluster_added.png b/assets/k3s_cluster_added.png new file mode 100644 index 0000000..b14bc0b Binary files /dev/null and b/assets/k3s_cluster_added.png differ diff --git a/assets/k3s_config_modify.png b/assets/k3s_config_modify.png new file mode 100644 index 0000000..3fba3b0 Binary files /dev/null and b/assets/k3s_config_modify.png differ diff --git a/assets/k3s_disk.png b/assets/k3s_disk.png new file mode 100644 index 0000000..45c453a Binary files /dev/null and b/assets/k3s_disk.png differ diff --git a/assets/k3s_kube_config.png b/assets/k3s_kube_config.png new file mode 100644 index 0000000..ad7602b Binary files /dev/null and b/assets/k3s_kube_config.png differ diff --git a/assets/k3s_nodes.png b/assets/k3s_nodes.png new file mode 100644 index 0000000..f2634a3 Binary files /dev/null and b/assets/k3s_nodes.png differ diff --git a/assets/k3s_reload.png b/assets/k3s_reload.png new file mode 100644 index 0000000..5f17022 Binary files /dev/null and b/assets/k3s_reload.png differ diff --git a/assets/k3s_status.png b/assets/k3s_status.png new file mode 100644 index 0000000..a3d56da Binary files /dev/null and b/assets/k3s_status.png differ diff --git a/assets/k8s_component.png b/assets/k8s_component.png new file mode 100644 index 0000000..81922b9 Binary files /dev/null and b/assets/k8s_component.png differ diff --git a/assets/k8s_deployment.png b/assets/k8s_deployment.png new file mode 100644 index 0000000..d64173c Binary files /dev/null and b/assets/k8s_deployment.png differ diff --git a/assets/k8s_describe_role.png b/assets/k8s_describe_role.png new file mode 100644 index 0000000..d6727f4 Binary files /dev/null and b/assets/k8s_describe_role.png differ diff --git a/assets/k8s_describe_sa.png b/assets/k8s_describe_sa.png new file mode 100644 index 0000000..249ffdb Binary files /dev/null and b/assets/k8s_describe_sa.png differ diff --git a/assets/k8s_describe_secret_sa.png b/assets/k8s_describe_secret_sa.png new file mode 100644 index 0000000..06a307a Binary files /dev/null and b/assets/k8s_describe_secret_sa.png differ diff --git a/assets/k8s_flow.png b/assets/k8s_flow.png new file mode 100644 index 0000000..184e6ea Binary files /dev/null and b/assets/k8s_flow.png differ diff --git a/assets/k8s_flow2.png b/assets/k8s_flow2.png new file mode 100644 index 0000000..a239f5a Binary files /dev/null and b/assets/k8s_flow2.png differ diff --git a/assets/k8s_flow3.png b/assets/k8s_flow3.png new file mode 100644 index 0000000..bfc9b73 Binary files /dev/null and b/assets/k8s_flow3.png differ diff --git a/assets/k8s_journey.png b/assets/k8s_journey.png new file mode 100644 index 0000000..0d7654a Binary files /dev/null and b/assets/k8s_journey.png differ diff --git a/assets/k8s_overview_1.png b/assets/k8s_overview_1.png new file mode 100644 index 0000000..e0a9347 Binary files /dev/null and b/assets/k8s_overview_1.png differ diff --git a/assets/k8s_overview_10.png b/assets/k8s_overview_10.png new file mode 100644 index 0000000..0b09a96 Binary files /dev/null and b/assets/k8s_overview_10.png differ diff --git a/assets/k8s_overview_2.png b/assets/k8s_overview_2.png new file mode 100644 index 0000000..a09591e Binary files /dev/null and b/assets/k8s_overview_2.png differ diff --git a/assets/k8s_overview_3.png b/assets/k8s_overview_3.png new file mode 100644 index 0000000..a534c01 Binary files /dev/null and b/assets/k8s_overview_3.png differ diff --git a/assets/k8s_overview_4.png b/assets/k8s_overview_4.png new file mode 100644 index 0000000..5a881f5 Binary files /dev/null and b/assets/k8s_overview_4.png differ diff --git a/assets/k8s_overview_5.png b/assets/k8s_overview_5.png new file mode 100644 index 0000000..32418fc Binary files /dev/null and b/assets/k8s_overview_5.png differ diff --git a/assets/k8s_overview_6.png b/assets/k8s_overview_6.png new file mode 100644 index 0000000..6d431dd Binary files /dev/null and b/assets/k8s_overview_6.png differ diff --git a/assets/k8s_overview_7.png b/assets/k8s_overview_7.png new file mode 100644 index 0000000..93e9b9b Binary files /dev/null and b/assets/k8s_overview_7.png differ diff --git a/assets/k8s_overview_8.png b/assets/k8s_overview_8.png new file mode 100644 index 0000000..bb91e1e Binary files /dev/null and b/assets/k8s_overview_8.png differ diff --git a/assets/k8s_overview_9.png b/assets/k8s_overview_9.png new file mode 100644 index 0000000..49e612c Binary files /dev/null and b/assets/k8s_overview_9.png differ diff --git a/assets/kt_cloud_vm_create.png b/assets/kt_cloud_vm_create.png new file mode 100644 index 0000000..32feb68 Binary files /dev/null and b/assets/kt_cloud_vm_create.png differ diff --git a/assets/kubeconfig_paste.png b/assets/kubeconfig_paste.png new file mode 100644 index 0000000..0993d88 Binary files /dev/null and b/assets/kubeconfig_paste.png differ diff --git a/assets/kubectl_download.png b/assets/kubectl_download.png new file mode 100644 index 0000000..f3f42fc Binary files /dev/null and b/assets/kubectl_download.png differ diff --git a/assets/kubectl_stable.png b/assets/kubectl_stable.png new file mode 100644 index 0000000..933304a Binary files /dev/null and b/assets/kubectl_stable.png differ diff --git a/assets/kubectl_version.png b/assets/kubectl_version.png new file mode 100644 index 0000000..111b537 Binary files /dev/null and b/assets/kubectl_version.png differ diff --git a/assets/kustomize_argocd_dev1.png b/assets/kustomize_argocd_dev1.png new file mode 100644 index 0000000..2cdc042 Binary files /dev/null and b/assets/kustomize_argocd_dev1.png differ diff --git a/assets/kustomize_argocd_dev2.png b/assets/kustomize_argocd_dev2.png new file mode 100644 index 0000000..0cce439 Binary files /dev/null and b/assets/kustomize_argocd_dev2.png differ diff --git a/assets/kustomize_argocd_dev3.png b/assets/kustomize_argocd_dev3.png new file mode 100644 index 0000000..1f26908 Binary files /dev/null and b/assets/kustomize_argocd_dev3.png differ diff --git a/assets/kustomize_base.png b/assets/kustomize_base.png new file mode 100644 index 0000000..03f72d2 Binary files /dev/null and b/assets/kustomize_base.png differ diff --git a/assets/kustomize_config.png b/assets/kustomize_config.png new file mode 100644 index 0000000..16bd723 Binary files /dev/null and b/assets/kustomize_config.png differ diff --git a/assets/kustomize_overlay.png b/assets/kustomize_overlay.png new file mode 100644 index 0000000..d4ba55a Binary files /dev/null and b/assets/kustomize_overlay.png differ diff --git a/assets/lens_cluster.png b/assets/lens_cluster.png new file mode 100644 index 0000000..44a8130 Binary files /dev/null and b/assets/lens_cluster.png differ diff --git a/assets/lens_cluster_list.png b/assets/lens_cluster_list.png new file mode 100644 index 0000000..84f36aa Binary files /dev/null and b/assets/lens_cluster_list.png differ diff --git a/assets/lens_config.png b/assets/lens_config.png new file mode 100644 index 0000000..ed4f53f Binary files /dev/null and b/assets/lens_config.png differ diff --git a/assets/lens_first_screeen.png b/assets/lens_first_screeen.png new file mode 100644 index 0000000..baac6d5 Binary files /dev/null and b/assets/lens_first_screeen.png differ diff --git a/assets/lens_metric_install.png b/assets/lens_metric_install.png new file mode 100644 index 0000000..74cf2d3 Binary files /dev/null and b/assets/lens_metric_install.png differ diff --git a/assets/lens_preview.png b/assets/lens_preview.png new file mode 100644 index 0000000..5e21c18 Binary files /dev/null and b/assets/lens_preview.png differ diff --git a/assets/lens_web.png b/assets/lens_web.png new file mode 100644 index 0000000..a73b76c Binary files /dev/null and b/assets/lens_web.png differ diff --git a/assets/lens_welcome.png b/assets/lens_welcome.png new file mode 100644 index 0000000..528fdf7 Binary files /dev/null and b/assets/lens_welcome.png differ diff --git a/assets/lens_welcome_0.png b/assets/lens_welcome_0.png new file mode 100644 index 0000000..228a2ce Binary files /dev/null and b/assets/lens_welcome_0.png differ diff --git a/assets/manage_jenkins1.png b/assets/manage_jenkins1.png new file mode 100644 index 0000000..1ef3e94 Binary files /dev/null and b/assets/manage_jenkins1.png differ diff --git a/assets/maven_user_setting.png b/assets/maven_user_setting.png new file mode 100644 index 0000000..72f3ff6 Binary files /dev/null and b/assets/maven_user_setting.png differ diff --git a/assets/model1.png b/assets/model1.png new file mode 100644 index 0000000..ab29d21 Binary files /dev/null and b/assets/model1.png differ diff --git a/assets/model2.png b/assets/model2.png new file mode 100644 index 0000000..a400604 Binary files /dev/null and b/assets/model2.png differ diff --git a/assets/model3.png b/assets/model3.png new file mode 100644 index 0000000..5f5ab13 Binary files /dev/null and b/assets/model3.png differ diff --git a/assets/modify1.png b/assets/modify1.png new file mode 100644 index 0000000..c13fd04 Binary files /dev/null and b/assets/modify1.png differ diff --git a/assets/modify2.png b/assets/modify2.png new file mode 100644 index 0000000..2ef5923 Binary files /dev/null and b/assets/modify2.png differ diff --git a/assets/modify3.png b/assets/modify3.png new file mode 100644 index 0000000..5baba4b Binary files /dev/null and b/assets/modify3.png differ diff --git a/assets/modify4.png b/assets/modify4.png new file mode 100644 index 0000000..5d8784c Binary files /dev/null and b/assets/modify4.png differ diff --git a/assets/modify5.png b/assets/modify5.png new file mode 100644 index 0000000..f59814e Binary files /dev/null and b/assets/modify5.png differ diff --git a/assets/modify6.png b/assets/modify6.png new file mode 100644 index 0000000..4e7c678 Binary files /dev/null and b/assets/modify6.png differ diff --git a/assets/modify7.png b/assets/modify7.png new file mode 100644 index 0000000..e7d80db Binary files /dev/null and b/assets/modify7.png differ diff --git a/assets/modify8.png b/assets/modify8.png new file mode 100644 index 0000000..cac1995 Binary files /dev/null and b/assets/modify8.png differ diff --git a/assets/modify9.png b/assets/modify9.png new file mode 100644 index 0000000..545d77e Binary files /dev/null and b/assets/modify9.png differ diff --git a/assets/mvc1.png b/assets/mvc1.png new file mode 100644 index 0000000..70144c7 Binary files /dev/null and b/assets/mvc1.png differ diff --git a/assets/mvc2.png b/assets/mvc2.png new file mode 100644 index 0000000..5a0338b Binary files /dev/null and b/assets/mvc2.png differ diff --git a/assets/mvc3.png b/assets/mvc3.png new file mode 100644 index 0000000..910f57a Binary files /dev/null and b/assets/mvc3.png differ diff --git a/assets/mvc4.png b/assets/mvc4.png new file mode 100644 index 0000000..972c701 Binary files /dev/null and b/assets/mvc4.png differ diff --git a/assets/mvc5.png b/assets/mvc5.png new file mode 100644 index 0000000..f566fe5 Binary files /dev/null and b/assets/mvc5.png differ diff --git a/assets/mvc6.png b/assets/mvc6.png new file mode 100644 index 0000000..c097975 Binary files /dev/null and b/assets/mvc6.png differ diff --git a/assets/mvc7.png b/assets/mvc7.png new file mode 100644 index 0000000..922359e Binary files /dev/null and b/assets/mvc7.png differ diff --git a/assets/mvc8.png b/assets/mvc8.png new file mode 100644 index 0000000..409401e Binary files /dev/null and b/assets/mvc8.png differ diff --git a/assets/mvc9.png b/assets/mvc9.png new file mode 100644 index 0000000..0442bcf Binary files /dev/null and b/assets/mvc9.png differ diff --git a/assets/new_namespace.png b/assets/new_namespace.png new file mode 100644 index 0000000..05c910f Binary files /dev/null and b/assets/new_namespace.png differ diff --git a/assets/node.png b/assets/node.png new file mode 100644 index 0000000..035d0e5 Binary files /dev/null and b/assets/node.png differ diff --git a/assets/nodeport_test.png b/assets/nodeport_test.png new file mode 100644 index 0000000..facf166 Binary files /dev/null and b/assets/nodeport_test.png differ diff --git a/assets/nodeport_traffic.png b/assets/nodeport_traffic.png new file mode 100644 index 0000000..234da72 Binary files /dev/null and b/assets/nodeport_traffic.png differ diff --git a/assets/okd_cluster_info_detail.png b/assets/okd_cluster_info_detail.png new file mode 100644 index 0000000..98eaca2 Binary files /dev/null and b/assets/okd_cluster_info_detail.png differ diff --git a/assets/okd_custer_info.png b/assets/okd_custer_info.png new file mode 100644 index 0000000..4b321aa Binary files /dev/null and b/assets/okd_custer_info.png differ diff --git a/assets/openshift_account.png b/assets/openshift_account.png new file mode 100644 index 0000000..c134dfe Binary files /dev/null and b/assets/openshift_account.png differ diff --git a/assets/pipeline_credential.png b/assets/pipeline_credential.png new file mode 100644 index 0000000..4565bc5 Binary files /dev/null and b/assets/pipeline_credential.png differ diff --git a/assets/pipeline_git.png b/assets/pipeline_git.png new file mode 100644 index 0000000..82590af Binary files /dev/null and b/assets/pipeline_git.png differ diff --git a/assets/pipeline_git2.png b/assets/pipeline_git2.png new file mode 100644 index 0000000..11066fa Binary files /dev/null and b/assets/pipeline_git2.png differ diff --git a/assets/pipeline_log_rotation.png b/assets/pipeline_log_rotation.png new file mode 100644 index 0000000..f5965d2 Binary files /dev/null and b/assets/pipeline_log_rotation.png differ diff --git a/assets/pipeline_main.png b/assets/pipeline_main.png new file mode 100644 index 0000000..7e0e766 Binary files /dev/null and b/assets/pipeline_main.png differ diff --git a/assets/pipeline_newitem.png b/assets/pipeline_newitem.png new file mode 100644 index 0000000..4f242cc Binary files /dev/null and b/assets/pipeline_newitem.png differ diff --git a/assets/pipeline_scriptpath.png b/assets/pipeline_scriptpath.png new file mode 100644 index 0000000..873cf24 Binary files /dev/null and b/assets/pipeline_scriptpath.png differ diff --git a/assets/plugin_git.png b/assets/plugin_git.png new file mode 100644 index 0000000..fb41bb0 Binary files /dev/null and b/assets/plugin_git.png differ diff --git a/assets/pod.png b/assets/pod.png new file mode 100644 index 0000000..dd38a27 Binary files /dev/null and b/assets/pod.png differ diff --git a/assets/port_forwarding1.png b/assets/port_forwarding1.png new file mode 100644 index 0000000..1fb034f Binary files /dev/null and b/assets/port_forwarding1.png differ diff --git a/assets/port_forwarding2.png b/assets/port_forwarding2.png new file mode 100644 index 0000000..7d6775d Binary files /dev/null and b/assets/port_forwarding2.png differ diff --git a/assets/portainer_admin.png b/assets/portainer_admin.png new file mode 100644 index 0000000..0c3bf60 Binary files /dev/null and b/assets/portainer_admin.png differ diff --git a/assets/portainer_container.png b/assets/portainer_container.png new file mode 100644 index 0000000..f8df15d Binary files /dev/null and b/assets/portainer_container.png differ diff --git a/assets/portainer_dashboard.png b/assets/portainer_dashboard.png new file mode 100644 index 0000000..29296e9 Binary files /dev/null and b/assets/portainer_dashboard.png differ diff --git a/assets/portainer_docker_volume.png b/assets/portainer_docker_volume.png new file mode 100644 index 0000000..86af205 Binary files /dev/null and b/assets/portainer_docker_volume.png differ diff --git a/assets/portainer_local.png b/assets/portainer_local.png new file mode 100644 index 0000000..cb1d26d Binary files /dev/null and b/assets/portainer_local.png differ diff --git a/assets/private_ip_create.png b/assets/private_ip_create.png new file mode 100644 index 0000000..d65b7f0 Binary files /dev/null and b/assets/private_ip_create.png differ diff --git a/assets/private_ip_info.png b/assets/private_ip_info.png new file mode 100644 index 0000000..4499e13 Binary files /dev/null and b/assets/private_ip_info.png differ diff --git a/assets/private_ip_modify.png b/assets/private_ip_modify.png new file mode 100644 index 0000000..c1d786f Binary files /dev/null and b/assets/private_ip_modify.png differ diff --git a/assets/private_ip_more.png b/assets/private_ip_more.png new file mode 100644 index 0000000..fdab0d7 Binary files /dev/null and b/assets/private_ip_more.png differ diff --git a/assets/project_overview.png b/assets/project_overview.png new file mode 100644 index 0000000..057a087 Binary files /dev/null and b/assets/project_overview.png differ diff --git a/assets/repository_create.png b/assets/repository_create.png new file mode 100644 index 0000000..9c6356c Binary files /dev/null and b/assets/repository_create.png differ diff --git a/assets/role_rolebinding.png b/assets/role_rolebinding.png new file mode 100644 index 0000000..aa8b448 Binary files /dev/null and b/assets/role_rolebinding.png differ diff --git a/assets/root_du_h.png b/assets/root_du_h.png new file mode 100644 index 0000000..bd585e5 Binary files /dev/null and b/assets/root_du_h.png differ diff --git a/assets/scale_out_after.png b/assets/scale_out_after.png new file mode 100644 index 0000000..c56e7e4 Binary files /dev/null and b/assets/scale_out_after.png differ diff --git a/assets/scale_out_before.png b/assets/scale_out_before.png new file mode 100644 index 0000000..69c7e84 Binary files /dev/null and b/assets/scale_out_before.png differ diff --git a/assets/service.png b/assets/service.png new file mode 100644 index 0000000..50a90c1 Binary files /dev/null and b/assets/service.png differ diff --git a/assets/service_type.png b/assets/service_type.png new file mode 100644 index 0000000..e02e060 Binary files /dev/null and b/assets/service_type.png differ diff --git a/assets/shclub_edu_file.png b/assets/shclub_edu_file.png new file mode 100644 index 0000000..f7924f3 Binary files /dev/null and b/assets/shclub_edu_file.png differ diff --git a/assets/swagger1.png b/assets/swagger1.png new file mode 100644 index 0000000..7480262 Binary files /dev/null and b/assets/swagger1.png differ diff --git a/assets/swagger2.png b/assets/swagger2.png new file mode 100644 index 0000000..ebdb58e Binary files /dev/null and b/assets/swagger2.png differ diff --git a/assets/swagger3.png b/assets/swagger3.png new file mode 100644 index 0000000..a1e1bc6 Binary files /dev/null and b/assets/swagger3.png differ diff --git a/assets/swagger4.png b/assets/swagger4.png new file mode 100644 index 0000000..9162cea Binary files /dev/null and b/assets/swagger4.png differ diff --git a/assets/swagger_first.png b/assets/swagger_first.png new file mode 100644 index 0000000..671f88f Binary files /dev/null and b/assets/swagger_first.png differ diff --git a/assets/swagger_second.png b/assets/swagger_second.png new file mode 100644 index 0000000..712ef16 Binary files /dev/null and b/assets/swagger_second.png differ diff --git a/assets/swagger_third.png b/assets/swagger_third.png new file mode 100644 index 0000000..8938097 Binary files /dev/null and b/assets/swagger_third.png differ diff --git a/assets/swagger_tool.png b/assets/swagger_tool.png new file mode 100644 index 0000000..6d5359e Binary files /dev/null and b/assets/swagger_tool.png differ diff --git a/assets/switch_context.png b/assets/switch_context.png new file mode 100644 index 0000000..78822dc Binary files /dev/null and b/assets/switch_context.png differ diff --git a/assets/top_nodes.png b/assets/top_nodes.png new file mode 100644 index 0000000..3342cec Binary files /dev/null and b/assets/top_nodes.png differ diff --git a/assets/update_app_dockerhub_v2.png b/assets/update_app_dockerhub_v2.png new file mode 100644 index 0000000..fe8554a Binary files /dev/null and b/assets/update_app_dockerhub_v2.png differ diff --git a/assets/update_app_jenkins2.png b/assets/update_app_jenkins2.png new file mode 100644 index 0000000..0d364a0 Binary files /dev/null and b/assets/update_app_jenkins2.png differ diff --git a/assets/update_app_v2.png b/assets/update_app_v2.png new file mode 100644 index 0000000..12ccec5 Binary files /dev/null and b/assets/update_app_v2.png differ diff --git a/assets/vi_dockerfile.png b/assets/vi_dockerfile.png new file mode 100644 index 0000000..d359a84 Binary files /dev/null and b/assets/vi_dockerfile.png differ diff --git a/assets/vi_k3s_service.png b/assets/vi_k3s_service.png new file mode 100644 index 0000000..5200e32 Binary files /dev/null and b/assets/vi_k3s_service.png differ diff --git a/assets/vi_tls_san.png b/assets/vi_tls_san.png new file mode 100644 index 0000000..8396978 Binary files /dev/null and b/assets/vi_tls_san.png differ diff --git a/assets/vm_created.png b/assets/vm_created.png new file mode 100644 index 0000000..aa2eb91 Binary files /dev/null and b/assets/vm_created.png differ diff --git a/assets/web_ingress.png b/assets/web_ingress.png new file mode 100644 index 0000000..ddff15a Binary files /dev/null and b/assets/web_ingress.png differ diff --git a/assets/youtube_daily.png b/assets/youtube_daily.png new file mode 100644 index 0000000..e5d226d Binary files /dev/null and b/assets/youtube_daily.png differ diff --git a/chapter1.md b/chapter1.md new file mode 100644 index 0000000..d7e3ab0 --- /dev/null +++ b/chapter1.md @@ -0,0 +1,800 @@ + +# Chapter 1 + +Docker에 대해서 자세한 설명과 함께 Jenkins CI 구성 요소인 Git에 대한 실습을 한다. + +1. Docker + +2. Dockerfile 구성 및 빌드 , Tag , Push 그리고 Swagger 실습 + +3. Jenkins를 사용한 CI 구성 하기 + + +## Docker + +
+ +### Docker 란 ? + +
+ +소개 및 배경 +- 도커는 컨테이너 기반의 오픈소스 가상화 플랫폼이다. +- 다양한 이유로 계속 바뀌는 서버 환경과 개발 환경 문제를 해결하기 위해 등장했다. + (툴 업데이트, 회사의 툴 사용 변경, 회사의 언어 정책 변경 등 ) +- 기존에 서버와 개발 환경이 변경되면 컴퓨터 셋팅(개발 환경) 등을 다시하거나 + 그 과정에서 발생하는 문제들과 같이, 여러모로 불편한 점이 많았다. +- 도커가 등장하고 서버관리/개발 방식이(컨테이너) 완전히 편리하게 바뀌게 된다. + +사용하는 이유 +- 도커 허브에 올라온 이미지와 docker-compose.yml의 설정으로 원하는 + 프로그램을 편안하게 설치가 가능하다. +- 컨테이너를 생성하여 분리된 환경에 설치하므로 제거도 쉽다. +- 하나의 서버(로컬 호스트)에 포트만 변경하여 동일한 프로그램을 실행하기도 쉽다. +- 도커를 사용하지 않으면 환경변수나 경로 등의 충돌로 피곤하기 그지 없다. + +서버관리 방식의 변화 +- 전통적인 서버관리 방식은 아래와 같이 각 단계별로 흐름이 있었고, 각 단계가 + 업데이트 되거나 어떤 문제가 발생하면 전체 흐름이 중단되는 문제가 있었다. +- 도커 등장 이후 어떠한 프로그램도 컨테이너로 만들 수 있다. +- 서로 다른 프로그램이더라도 컨테이너로 규격화 되었음 +- AWS, Azure, Google cloud 등 어떤 환경에서도 돌아간다. + +- 가상머신과 비슷하게 생각할 수 있지만 비슷한점과 다른점이 있다. +- 가상머신처럼 독립적으로 실행되지만, 가상머신보다 빠르고 쉽고 효율적이다. +- 도커는 컴퓨터 자원을 그대로 사용한다. + +도커의 특징 +- 도커는 가상머신이 아니고 격리만 해주기 떄문에 성능상 하락이 없다. (성능 하락이 큰 VM과 다르다.) +- 확장성과 이식성 + - 도커가 설치되어 있다면 어디서든 컨테이너를 실행할 수 있다. + - 오픈 소스이기에 특정 회사나 서비스에 종속적이지 않다. + - 쉽게 개발서버를 만들 수 있고 테스트 서버 생성도 가능하다. +- 표준성 + - 도커를 사용하지 않는 경우, 각각의 언어로 만든 서비스들의 배포 방식은 모두 다르다. + - 도커는 컨테이너라는 표준으로 서버를 배포하므로 모든 서비스들의 배포 과정이 동일해진다. +- 이미지 + - 컨테이너를 실행하기 위한 압축파일과 같은 개념이다. + - 이미지에서 컨테이너를 생성하기 떄문에 반드시 이미지를 만드는 과정이 필요하다. + - Dockerfile을 이용하여 이미지를 만들고 처음부터 재현 가능하다. + - 빌드 서버에서 이미지를 만들면 해당 이미지를 이미지 저장소(허브)에 저장하고 운영서버에서 이미지를 불러와 사용한다. +- 설정관리 + - 도커에서 설정은 보통 아래와 같이 환경변수로 제어한다. + - MYSQL_PASS=password와 같이 컨테이너를 띄울 때 환경변수를 같이 지정한다. + - 하나의 이미지가 환경변수에 따라 동적으로 설정파일을 생성하도록 만들어져야한다. +- 자원관리 + - 컨테이너는 삭제 후 새로 만들면 모든 데이터가 초기화된다. (제거가 쉽다.) + - 그러므로 저장이 필요하다면, 업로드 파일을 외부 스토리지와 링크하여 사용하거나 S3같은 별도의 저장소가 필요하다. + - 세션이나 캐시를 memcached나 redis와 같은 외부로 분리한다. + +
+ +Github 소스를 다운 로드 하기 위하여 Git을 설치 해야 한다. + +
+ +## Git + +### Git 개요 + +Git이란 소스코드를 효과적으로 관리하기 위해 개발된 '분산형 버전 관리 시스템'입니다. ( 이전 에는 SVN 많이 사용 ) + +가장 대중적인 SaaS 형태는 Microsoft에서 제공하는 GitHub 이고 +Private 형태로는 Gitlab을 많이 사용 함. + +
+ +참고 사이트 : https://backlog.com/git-tutorial/kr/intro/intro1_1.html + +
+ +### Git 설치. + +
+ +본인의 PC에 git을 설치하고 버전을 확인한다. + +```bash +git --version +``` + + + +
+ +### Git Clone 하여 github 소스 가져오기. + +github에서 shclub/edu2 를 선택하고 code를 클릭한다. +https의 url를 복사한다. 오른쪽 복사 아이콘 클릭 + + + +터미털에서 git clone 명령어를 사용하여 로컬에 소스를 가져온다. +정상적으로 가져오면 edu2 폴더로 이동하여 파일 받아진것 확인한다. + +```bash +git clone https://github.com/shclub/edu2.git +``` + + + + +
+ + +### Dockerfile + +
+ +도커 이미지를 만들기 위해서는 Dockerfile 을 생성 해야 한다. + +Dockerfile 예제 + +```yaml + +# 베이스 이미지 이며 이미지 이름 앞에 아무것도 없으면 docker hub에서 가져온다. +FROM python:3.8-slim + +# 컨테이너 안에 작업 폴더를 설정한다. +WORKDIR /app + +# 로컬 현대 폴더의 모든 값을 컨테이너 /app 폴더에 복사한다. +ADD . /app + +# pyhon의 경우 library를 requirements.txt에 기술을 하였고 RUN 명령어를 # 사용하여 아래 구문을 실행한다. + +# RUN pip install -r requirements.txt + +# 직접 라이브러리를 추가 할수 있다. 단 라이브러리가 많아지면 불편하다. +RUN pip3 install flask==2.0.3 +RUN pip3 install flask-cors==3.0.10 +RUN pip3 install flask_restx +RUN pip3 install Werkzeug==2.0.3 + +# 기본 이미지는 대부분 GMT+0 기준으로 생성되어 한국 시간으로 변경 해준다 +RUN ln -snf /usr/share/zoneinfo/Asia/Seoul /etc/localtime && echo Asia/Seoul > /etc/timezone + +# 컨테이너 외부에서 접속할 포트를 적어준다. +EXPOSE 40003 + +# 컨테이너 로딩시에 사용하는 명령어를 기입한다. +# EntryPoint와 비슷 하나 CMD를 사용하면 docker run시에 파라미터 설정 가능하다. +CMD ["python", "app.py"] +``` + +터미널에서 edu2 폴더로 이동하여 vi 에디터로 Dockerfile를 생성한다. + +```bash +vi Dockerfile +``` + + + +
+ +i (소문자) 를 누른 후 위의 Dockerfile 내용을 복사하여 붙여넣기 한다. +esc 키를 누른 후 :wq를 입력하여 저장하고 나온다. + + +그리고 app.py 화일을 아래 소스를 사용하여 생성한다. + +```bash +vi app.py +``` + +app.py + + +```python +# -*- coding:utf-8 -*- +# REST API로 구현한 계산기 예제 + +import werkzeug +werkzeug.cached_property = werkzeug.utils.cached_property + +from flask import Flask +from flask_restx import Resource, Api, reqparse + + +# ----------------------------------------------------- +# api +# ----------------------------------------------------- +app = Flask(__name__) +api = Api(app, version='1.0', title='Calc API', + description='계산기 REST API 문서',) + +ns = api.namespace('calc', description='계산기 API 목록') +app.config.SWAGGER_UI_DOC_EXPANSION = 'list' # None, list, full + + +# ----------------------------------------------------- +# 덧셈을 위한 API 정의 +# ----------------------------------------------------- +sum_parser = ns.parser() +sum_parser.add_argument('value1', required=True, help='연산자1') +sum_parser.add_argument('value2', required=True, help='연산자2') + + +@ns.route('/sum') +@ns.expect(sum_parser) +class FileReport(Resource): + def get(self): + """ + Calculate addition + """ + args = sum_parser.parse_args() + + try: + val1 = args['value1'] + val2 = args['value2'] + except KeyError: + return {'result': 'ERROR_PARAMETER'}, 500 + + result = {'result': 'ERROR_SUCCESS','value': int(val1) + int(val2)} + return result, 200 + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000) # , debug=True) +``` + +
+아래 명령어를 사용하여 도커 파일을 생성한다. +Dockerfile 위치와 같은 폴더에서 실행하여야 하며 생성할 이미지 이름 뒤에 . 을 반드시 사용한다. + +```bash +docker build -t edu2 . +``` + + + +Dockerfile의 line by line 으로 단계가 구성되어 도커 레이어를 생성을 한다. +내부 적으로는 docker commit 명령어가 실행이 되면 도커를 재 생성시에는 +Cache를 사용 하기 때문에 훨씬 빨리 빌드가 된다. + + + +중간에 임시에 생성된 intermediate 컨테이너가 삭제가 되고 빌드 이미지가 만들어진다. + +아래 명령어를 사용하여 생성된 도커 이미지를 확인 할 수 있다. + +```bash +docker images +``` + + + +Docker Hub에 전송하기 위해서는 tagging을 하고 push를 한다. +tag 명령어 뒤에는 로컬 이미지 이름 , 다음에는 도커허브 이미지 이름을 입력. + +```bash +docker tag edu2 (본인 도커 허브 ID)/edu2 +docker push (본인 도커 허브 ID)/edu2 +``` + + + +Docker Hub에 페이지에서 push된 이미지를 확인한다. + + + +실행 중인 컨테이너를 확인하고 40003 포트를 사용하는 컨테이너를 stop 한다. +```bash +docker ps +docker stop (컨테이너id) +``` + + + +도커 이미지를 실행한다. +- -d : Detached 모드(백그라운드) +- --name : 컨테이너에 이름을 부여한다. +- -p : 포트 ( 외부접속포트 : 컨테이너 포트) +- 맨 마지막에 도커 이미지 이름 + +```bash +docker run -d --name my-python -p 40003:5000 (본인 도커 허브 ID)/edu2 +``` + +docker ps 명령어로 정상적인지 확인한다. + + + +docker ps 로 아무 것도 없으면 docker ps -a 명령어도 kill 된 컨테이너를 확인하고 +docker logs 명령어로 로그를 확인한다. + + +```bash +docker logs (컨테이너id) +``` + + +에러가 발생한 도커는 같은 이름으로 docker run 명령어를 실행 하면 에러가 발생하기 때문에 아래 명령어를 실행 후에 위의 docker run 명령어를 다시 실행한다. + +```bash +docker rm (컨테이너 이름) +``` + +docker 컨테이너 안으로 들어가 본다. + +```bash +docker exec -it (컨테이너id) /bin/sh +``` + +컨테이너 내부에서 ls 명령어를 쳐보면 도커 빌드시 복사되었던 소스를 확인 할 수 있다. + + + +exit 명령어를 사용하여 컨테이너 내부에서 나올수 있다. + +현재 컨테이너의 내용을 도커 이미지로 저장하고 싶을때는 commit 명령어를 사용한다. +- -m : 뒤에 comment를 적어준다 +- 컨테이너 이름 : 현재 실행되는 컨테이너 이름 또는 컨테이너 아이디를 적여준다 +- 신규 도커 이미지 : 신규로 생성하고 싶은 로컬 도커이미지 이름을 적어준다 + +```bash +docker commit -m "new edu2" (컨테이너 이름) (생성하고싶은 이미지 이름):(버전) +``` + + + +docker stats 명령어를 사용하면 컨테이너별로 CPU/MEM을 볼 수 있다. + +```bash +root@jakelee:~# docker stats +``` + + + +
+ +도커 추가 명령어 +- 정지 중인 컨테이너 삭제 : docker container prune +- 이미지 , 정지되어 있는 컨테이너 , 네트웍크 삭제 : docker system prune +- 도커 이미지 삭제 : docker rmi (도커 로컬 이미지 이름) +- 컨테이너 삭제 : docker rm [CONTAINER_ID] +- 컨테이너 일시정지 : docker stop [CONTAINER_ID] + +
+ +## GitHub 계정을 생성 + +
+ +### https://github.com/ 접속하고 계정 생성 + +
+ +### 계정 생성 후에 Repository를 생성한다. + +아래와 같이 이름 입력를 하고 README file check 를 한다. + + + +default 브랜치를 main에서 master로 변경한다. ( 맨 하단 setting 클릭하여 설정) + + + +
+ +### 교육용 repository인 https://github.com/shclub/edu1 를 fork 하여 본인의 Repository에 복사한다. + +총 4개 화일을 만들고 내용을 복사한다. + + + + - 샘플은 pyhon flask 로 구성 + +

+ +## Docker Hub 계정을 생성 + +
+ +### https://hub.docker.com/ 접속하고 계정 생성 (향후 사내에서 개발시는 d-space Nexus 사용) + +
+ +### Docker 연동 테스트를 한다. + +```bash +docker tag hello-world (본인id)/hello-world +docker push (본인id)/hello-world +``` + +- 권한 에러 발생시 docker login 한다 +```bash +docker login +``` + + + +정상적으로 로그인후 push를 한다. + +```bash +docker push (본인id)/hello-world +``` + + + +도커허브 본인 계정에서 도커 이미지 생성 확인 + + + + +도커 이미지가 Private으로 되어 있으면 Public 으로 변경한다. +- 개인 계정은 1개의 private 만 가능 + +setting 으로 이동하여 Make public 클릭후 repository 이름을 입력후 Make Public 클릭 + + + +

+ +## Jenkins 설정 + +
+ +### 일반 사용자 계정을 생성한다 + +웹 브라우저에서 http://211.252.85.148:9000/ 로 이동하여 로그인 한다. +교육 계정은 기 생성 되어 있다. ( edu1 ~ edu25 ) + +비밀번호는 계정 이름과 동일. + +
+ + +Manage Jenkins -> Manage Users 로 이동한다. 사용자 생성 버튼 클릭 후 사용자 생성. + + + +
+ +### 계정 별 권한 부여방법 + +
+ +Configure Global Security로 이동 + +admin 계정으로 테스트 할 예정 으로 skip. + + + + +생성한 계정을 입력하고 Add 클릭 추가후 권한 설정은 일단 Ovrall 체크 후 저장 +Project-based Matrix Authorization Strategy 체크 후 권한 설정 + + + +
+ +### Github token 생성하기 + +
+ +웹브라우저에서 Github 로그인하고 +Jenkins 에서 github repository 인증을 위해 사용할 token 을 생성한다. + +- Settings - Developer settings - Personal access tokens - Generate token +선택해서 토큰 생성 + +Github 사이트의 오른쪽 상단 본인 계정의 Setting으로 이동한다. ( 프로젝트의 setting이 아님 ) + + + +
+ +Expiration 은 No Expiration으로 선택하고 repo, admin:repo_hook 만 체크하고 Generation Token 버튼 클릭해서 토큰 생성 + + + + +복사 아이콘을 클릭하여 토큰 값을 복사한다. +- 다시 페이지에 들어가면 보이지 않아서 복사 후 저장 필요 + + + +
+ +### GitHub Credential을 생성한다. + +
+ +Jenkins가 GitHub에서 Code를 가져올 수 있도록 Credential을 추가하자 + +- Manage Jenkins -> Manage Credential -> System 으로 이동한다. + + + +Global Credential 클릭 + + + +Add Credential를 클릭하면 계정 설정하는 화면이 나온다. + + + +Kind는 Username with password 를 선택해주시면 됩니다. + +Username 은 본인의 Github ID 를 선택해주시면 됩니다. ( 이메일 아님 ) + +ID는 본인이 원하는 식별자를 넣어준다. + +password는 이전에 발급받은 Github Token 값을 입력한다. + + + +
+ +### Docker Hub Credential을 생성한다. + +
+ +Jenkins가 Docker Hub에 Image를 push 할 수 있도록 Credential을 추가하자 + +- Manage Jenkins -> Manage Credential -> System -> Global Credential 로 이동한다. + +
+ +Add Credential를 클릭하면 계정 설정하는 화면이 나온다. + +Kind는 Username with password 를 선택해주시면 됩니다. + +Username 은 본인의 Docker Hub ID 를 선택해주시면 됩니다. ( 이메일 아님 ) + +ID는 본인이 원하는 식별자를 넣어준다. + +password는 이전에 Docker Hub 본인 계정의 비밀번호 값을 입력한다. + + + +
+ +GitHub와 Docker Hub Credential 이 생선된 것을 확인한다. + + + +
+ +### 파이프 라인을 구성한다. + +
+ +메인 화면 좌측 메뉴에서 새로운 Item 선택 + + + +item 이름을 입력하고 Pipeline 을 선택 후에 OK + + + +로그 Rotation을 5로 설정한다. 5개의 History 를 저장한다. + + + +Jenkins 홈 폴더로 이동하고 아래 명령어를 실행한다. + +- 홈 폴더 확인은 대쉬보드에서 Manage Jenkins -> Configure System으로 이동하여 보면 상단에 표시 + + + + +```bash +cd /var/lib/jenkins +ls ./jobs/edu1/builds +``` + +7개의 History중 3,4,5,6,7 5개만 저장된것을 확인 할 수있다. + + + + +대쉬보드에서도 History를 확인 할 수 있다. + + + +
+ +Github Project URL을 설정하고 Git Parameter 를 체크하고 Parameter Type은 교육을 위한 용도 임으로 Branch를 선택한다. ( Tag는 Release를 위한 빌드 방식으로 그 당시 snapshot 이다. ) + +Branch의 default는 orgin/master를 설정한다. + + + +
+ +* Tag 를 사용한 빌드는 맨 아래 부분을 참고한다. + +
+ +Build Triggers - GitHub hook trigger for GITScm polling 선택 +Repository 에 Git Url을 입력한다. +Credential에 Jenkins에서 생성한 github_ci를 선택하여 추가한다. + + + + +Script Path는 Jenkinsfile 로 설정한다. +github에 대소문자 구문하여 Jenkinsfile 이 있어야함. +Save 버튼을 클릭하여 저장한다. + + + +
+ +### 빌드 실행 + +
+ +빌드 하기 전에 Jenkins 화일로 이동하여 docker hub 의 repository와 docker credential은 본인의 계정으로 설정한다. + +대쉬보드에서 Build With Parameter를 선택하고 Branch 선택 후 빌드 한다. + + + +빌드가 진행 되는 것을 단계별로 확인 할 수 있다. + + + +에러가 발생하면 해당 단계에서 마우스 오른쪽 버튼을 클릭하여 로그 확인 할수 있다. +또한 왼쪽 하단의 Build History 에서 해당 빌드 번호를 클릭하여 자세한 에러를 볼수 있다. + + + +Console Output을 선택하고 에러를 확인 할 수 있다. + + + +아래 에러는 docker hub에서 repository가 private 으로 설정이 되어 발생한 에러이고 위에 설명한 대로 public 으로 변경하면 에러가 발생하지 않는다. + + + +대쉬보드에서 해당 파이프라인인 edu1을 선택하고 다시 빌드 한다. + + + +성공적으로 완료된 화면을 볼 수 있다. + + + +Docker Hub에서 정상적으로 생성된 이미지를 확인 할수 있다. + + + +* Docker build에 에러가 발생하는 경우가 있는데 Jenkins plugins가 정상적을 + 설치가 안되어 있을수 있다. + docker 검색하여 제대로 설치가 되어 있는지 확인 하고 없으면 재 설치 한다. + +
+ +### Docker pull 및 실행 테스트 + +
+ +터미널로 VM 서버에 접속하여 생성된 도커이미지를 다운로드(pull)하고 실행 (run) + +```bash +docker pull shclub/edu1 +``` + + + +```bash +docker run -p 40003:8080 shclub/edu1 +``` +Python Flask 가 정상적으로 로드가 된걸 확인 할 수 있다. + + + +브라우저에서 localhost:40003 호출하여 Hello World 확인 + + + +
+ +- 과제 : github webhook를 통한 빌드 자동화 ( git push 하면 자동 빌드 ) + +
+ +### Jenkinsfile 설명 + +
+ +Jenkins 화일에서 github와 docker credential 은 Jenkins 설정에서 Credential을 생성한 +id를 입력하면 된다. + +반드시 본인이 만든 값으로 Jenkins파일의 수정해야 함. + + + +Jenkins에 설정된 credential + + + + +Jenkins Stage View 를 통해 Step별 진행 사항을 볼수 있다. + + + + +
+ +### Jenkins 환경변수 + +
+ +env 환경변수는 다음과 같은 형식 env.VARNAME으로 참조될 수 있다. 대표적인 env의 property는 아래와 같다. + + + +
+ +currentBuild 환경변수는 현재 빌드되고 있는 정보를 담고있다. 보통 readonly 옵션인데 일부 writable한 옵션이 존재한다. 대표적인 currentBuild의 property는 아래와 같다. + + + + +환경 변수 사용 예제. + +```bash +pipeline { + agent any + stages { + stage('Example') { + steps { + echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}" + } + } + } +} +``` + + + +
+ +### Tag를 사용한 Jenkins 빌드 + +
+ +Tag를 사용한 빌드는 운영(Release)를 위해 주로 사용하며 Tagging하는 순간의 snapshot 이다. + +Git Parameter에서 Tag를 선택하고의 default는 RB.0.1 을 임으로 설정한다. + + + +
+ +GitHub 로 이동 한후 Repository를 선택 한 후 code Tab 으로 들어간다. +Tags 아이콘을 클릭한다. + + + +Tags를 선택하고 Create new release 버튼을 클릭한다. + + + +Choose a tag를 클릭하면 tag이름을 입력하는 text 박스가 나온다. + + + +생성하고 싶은 Tag 이름을 입력한다. +jenkins pipeline에서 RB.0.1을 기본값으로 설정을 해서 같은 이름으로 입력한다. +입력창 아래 생성된 + Create new tag : RB.0.1 클릭 + + + +Title 값을 입력 ( 원하는 이름 아무거나 입력 ) 하고 Publish release 버튼을 클릭한다 + + + +
+ +Jenkins 대쉬보드에서 Build with Parameters 선택하면 Tag이름이 RB.0.1로 기본값이 설정된다. + +Tag를 선택하고 Build 버튼을 클릭하면 해당 Tag의 소스로 빌드가 된다. + + + +
\ No newline at end of file diff --git a/chapter2.md b/chapter2.md new file mode 100644 index 0000000..7afd0c8 --- /dev/null +++ b/chapter2.md @@ -0,0 +1,534 @@ + +# Chapter 2 + +Jenkins CI 구성 요소인 Git , Docker에 대해서 자세한 설명과 함께 Docker Compose 에 대해서도 실습을 한다. + + + +1. GitHub Action와 Workflow 실습하기 + +2. Docker compose 설치 및 WordPress, SQL 구성 예제 실습 + +
+ +## Github action 과 workflow 사용하여 도커 이미지 생성 ( Goodbye Jenkins ) + +
+ +### GitHub Package + +
+ +github 에서도 Packages 라는 이름으로 도커 레지스트리를 기능을 지원한다. +현재 private은 500 메가 까지는 제공을 하고 있다. + +docker 이미지 이름은 앞에 ghcr.io가 붙는다. +github의 본인 계정으로 이동하면 packages tab을 볼수 있다. + + + +
+ +### GitHub Docker 이미지 빌드 후 github package 에 push + +
+ +우리가 그동안 Jenkins 를 통하여 Docker Build 를 수행 했지만 이제는 +Github의 Action , workflow 기능을 이용하여 빌드를 수행해본다. + +
+ +https://github.com/shclub/edu7 를 본인의 github에 fork 한다. + +Actions tab 을 클릭한다. + + + +템플릿 목록이 나오고 먼저 Github package 에 push 하기 위해서 Publish Docker Container Template을 선택한 후 configure 를 클릭한다. +- IOS 나 Android의 경우는 search 메뉴에서 검색한다. + + + +docker-publish.yml 화일이 아래 처럼 생기고 schedule 부분의 2개 라인만 +주석 처리하고 Start commit을 클릭한다. + + + +./github/workflows 폴더가 생성이 되고 docker-publish.yml 화일이 생성 된것을 확인 할수 있다. + + + +다시 Actions Tab을 클릭한다. +Docker 라는 workflow 가 생성이되고 오른편에 pipeline 이 실행 되고 있는것을 확인할 수있다. + + + +정상적으로 수행이되면 파란색으로 아이콘이 변경이되고 에러가 발생하면 붉은색으로 나온다. + + + +해당 파이프라인 클릭 ( create Docker-publish.yml ) 하면 빌드 화면으로 넘어가고 Build를 클릭하면 오른편에 파이프라인 세부 로그를 볼 수있다. + + + +생성된 빌드 이미지를 보기 위해서는 본인 계정을 클릭한다. + + + +repository에서도 오른편에서 package 를 통해 확인 할 수도 있다. + + + +Packages를 클릭하면 신규로 생성된 도커 이미지를 확인 할 수 있다. + + + +해당 도커 이미지를 클릭하면 docker pull을 위한 도커 이미지를 명령어를 확인 할 수 있고 오른편에는 +package를 설정할수 있다. + +기본 설정은 public 이다. + + + +생성된 도커를 터미널 창에서 아래와 같이 실행한다. +기본 tag는 master 이다. + + +```bash +root@jakelee:~# docker run ghcr.io/shclub/edu7:master + * Serving Flask app 'app' (lazy loading) + * Environment: production + WARNING: This is a development server. Do not use it in a production deployment. + Use a production WSGI server instead. + * Debug mode: off + * Running on all addresses (0.0.0.0) + WARNING: This is a development server. Do not use it in a production deployment. + * Running on http://127.0.0.1:5000 + * Running on http://172.17.0.2:5000 (Press CTRL+C to quit) + ``` + + +
+ +### GitHub Docker 이미지 빌드 후 docker hub 에 push + +
+ +GitHub package 가 아닌 Docker hub 에 push 해본다. + +Actions Tab으로 이동하여 New workflow를 클릭한다. + + + +아래의 내용을 복사한다. + +```bash +name: Publish Docker image + +on: +# release: +# types: [published] + push: + branches: [ master ] + # Publish semver tags as releases. +# tags: [ 'v*.*.*' ] + pull_request: + branches: [ master ] + +jobs: + push_to_registry: + name: Push Docker image to Docker Hub + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: shclub/edu7 + + - name: Build and push Docker image + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + push: true + tags: shclub/edu7 + #${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} +``` + +아래와 같이 생성이 되면 화일명을 docker-hub-publish.yml로 변경을 하고 image 이름을 원하는 이름으로 변경한다. +본인 docker hub id 를 사용한다. + +```bash +#before + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: shclub/edu7 + + - name: Build and push Docker image + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + push: true + tags: shclub/edu7 + labels: ${{ steps.meta.outputs.labels }} +#after + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: <본인 도커 계정>/edu7 <-- 수정 + + - name: Build and push Docker image + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + push: true + tags: <본인 도커 계정>/edu7 <-- 수정 + labels: ${{ steps.meta.outputs.labels }} +``` + + + +start commit 버튼을 클릭하면 화일이 신규로 생긴것을 확인할 수가 있고 빌드가 수행이 된다. + + + +Actions Tab 으로 이동하면 Publish Docker image 가 생성이 되고 빌드 파이프 라인이 성공 1개 에러 1개가 발생 한 것을 확인 할 수 있다. + + + +에러를 클릭하면 세부 파이프라인 창으로 이동을 하고 오른편 화면에 에러가 난 곳을 확장 하여 에러메시지를 +확인한다. + +에러 메시지는 Github Repository (edu7)에 도커 허브 credential을 만들지 않아서 발생한 에러이다. + + + +도커 허브 Credential을 만들기 위해서 setting -> secret 으로 이동하여 Action을 클릭한다. + + + +New Repository Secret를 클릭한다. + + + +docker-hub-publish.yml 에 생성한 것처럼 설정을 한다. + +```bash +with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} +``` + +아래와 같이 secret을 생성한다. + + + +2개의 secret이 생성된 것을 확인 할수 있다. + + + +Actions Tab 으로 이동하여 Publish Docker image 를 선택하고 에러난 화면을 클릭하여 세부 파이프라인 창으로 이동한다. + + + +오른쪽 상단에 Re-run failed job을 선택한다. + + + +Re-run jobs를 클릭한다. + + + +다시 파이프라인을 재실행을 한다. + + + +성공으로 빌드 된것을 확인 할 수 있다. + + + +도커 허브로 이동하여 생성된 이미지를 확인한다. + + + + +
+ +### 수동으로 Actions workflow 실행 + +
+ +workflow는 schedule 또는 event trigger를 통해서 동작을 하지만 수동으로 원할때만 빌드 할수 있도록 구성을 할 수 있다. + +
+ +docker-hub-publish.yml 화일에서 on 아래에 아래와 같이 추가해 준다. +기존의 값은 주석 처리한다. ( jobs 아래 내용은 수정하지 않는다 ) + +```bash +on: + workflow_dispatch: + inputs: + name: + description: "TAG" + required: true + default: "master" +# schedule: +# - cron: '25 2 * * *' +# push: +# branches: [ master ] +# # Publish semver tags as releases. +# tags: [ 'v*.*.*' ] +# pull_request: +# branches: [ master ] +``` + +Commit을 하고 Actions Tab으로 이동하면 아래와 같이 Run workflow 버튼이 생성된 것을 확인 할 수 있다. + +버튼을 클릭하면 설정한 Input 값이 나오고 Run을 하면 실행이 된다. + + + + +## Docker Compose + +
+ +### Docker Compose 개요 + +Docker compose란, 여러 개의 컨테이너로부터 이루어진 서비스를 구축, 실행하는 순서를 자동으로 하여, 관리를 간단히하는 기능이다. + + Docker compose에서는 compose 파일을 준비하여 커맨드를 1회 실행하는 것으로, 그 파일로부터 설정을 읽어들여 모든 컨테이너 서비스를 실행시키는 것이 가능하다. + +### Docker Compose를 사용하기까지의 주요한 단계 + +Docker compose를 사용하기 위해서는, 크게 나눠 아래의 세 가지 순서로 이루어진다. + +1) 각각의 컨테이너의 Dockerfile를 작성한다(기존에 있는 이미지를 사용하는 경우는 불필요). + +2) docker-compose.yml를 작성하고, 각각 독립된 컨테이너의 실행 정의를 실시한다(경우에 따라는 구축 정의도 포함). + +3) "docker-compose up" 커맨드를 실행하여 docker-compose.yml으로 정의한 컨테이너를 개시한다. + + Docker compose는 start, stop, status, 실행 중의 컨테이너의 로그 출력, 약간의 커맨드의 실행이과 같은 기능도 가지고 있다. + +
+ +### Docker Compose 설치 + +본인 VM에 터미널로 접속하여 아래 명령어를 입력한다. + +```bash +apt-get update && apt install docker-compose +``` +중간에 추가 설치 내용이 나오면 Y를 입력하고 엔터를 친다. + + + +도커 컴포즈 버전을 확인하고 아래와 같이 나오면 정상적으로 설치가 된 것이다. + +```bash +docker-compose --version +``` + + +### Docker Compose yaml + +도커 실행 명령어를 yml 파일로 스크립트 문서화 하여 관리한다. + +이번 예제는 워드프레스(WordPress)라는 오픈 소스 블로그 소프트웨어 이고 +워드 프레스를 통해서 PHP기반의 웹페이지를 만들수 있다. +기본적으로 Mysql DB를 내장하고 있다. + + +터미널로 접속하여 새로운 폴더를 하나 생성하고 생성된 폴더로 이동한다. +vi 에디터로 docker-compose.yml 를 생성한다. + +```bash +mkdir edu2-1 +cd edu2-1 +vi docker-compose.yml +``` + + + +아래의 내용을 복사하여 docker-compose.yml에 붙여 넣기한다. +esc 눌러주고 :wq를 입력하여 저장하고 나온다. + + +```yaml +version: '3.3' + +services: + db: + image: mysql:5.7 + volumes: + - ./mysql:/var/lib/mysql + restart: always + environment: + MYSQL_ROOT_PASSWORD: wordpress + MYSQL_DATABASE: wordpress + MYSQL_USER: wordpress + MYSQL_PASSWORD: wordpress + wordpress: + depends_on: + - db + image: wordpress:latest + ports: + - "40004:80" + restart: always + environment: + WORDPRESS_DB_HOST: db:3306 // mysql 기본 설정 + WORDPRESS_DB_USER: wordpress + WORDPRESS_DB_PASSWORD: wordpress + WORDPRESS_DB_NAME: wordpress + volumes: + - ./wp:/var/www/html +``` + +맥 M1 사용자는 M1용 mysql 도커 이미지가 없어 아래의 샘플로 테스트 한다. + + +```yaml +version: '3.3' +services: + frontend: + image: ghcr.io/shclub/edu12-3:master + depends_on: + - backend + environment: + API_URL: http://backend:8080 + ports: + - 3000:80 + backend: + image: ghcr.io/shclub/edu12-4:master + container_name: backend + environment: + SPRING_PROFILES_ACTIVE: dev + ports: + - 8092:8080 + db: + image: mysql + restart: always + volumes: + - ./mysql/:/var/lib/mysql/ + ports: + - 3306:3306 + environment: + MYSQL_ROOT_PASSWORD: edu1234 + MYSQL_USER: edu + MYSQL_PASSWORD: edu1234 + MYSQL_DATABASE: edu +``` +
+ +Docker compose 명령어를 사용하여 컨테이너를 실행한다. + +```bash +docker-compose up -d +``` + +- 현재 디렉토리에 있는 docker-compose 파일을 실행하여, docker-compose 파일에 정의된 컨테이너를 실행한다. +- -d 옵션을 주면 detached(백그라운드)으로 실행한다. +- –force-recreate 옵션으로 컨테이너를 새로 만들 수 있다. +- –build 옵션으로 도커 이미지를 다시 빌드한다. (build로 선언했을 때만) + + + + +Docker ps를 해보면 2개의 컨테이너가 떠 있는 것을 확인 할 수 있다. + +```bash +docker ps 또는 docker-compose ps +``` + + + + +해당 폴더를 보면 .wp 와 .mysql 폴더가 생성 된 것을 확인 할수 있다. + +```bash +ls +``` + + +docker compose 기동시에 volumes 설정이 로컬 폴더와 컨테이너 폴더를 연결 한것 을 볼수 있다. + + + +브라우저를 통해서 http://localhost:40004로 접속하여 정상적으로 로드 된걸 확인 할 수 있다. + +도커 컴포즈 명령어 +- 컨테이너 종료 : docker-compose down +- 컨테이너 정지 : docker-compose stop +- 컨테이너 로그 보기 : docker-compose logs +- 컨테이저 재시작 : docker-compose restart +- stop으로 정지 된 컨테이너 시작 : docker-compose start +- 도커 네트웍 지우기 : docker network prune + + + +다른 docker-compse를 테스트 하기 위해서는 폴더를 새로 만든 후 docker-compose.yaml를 만들고 해당 폴더에서 명령어를 수행한다. + +
+ +## 과제 + +
+ +### 과제 1 + + + docker compose로 구성한 mysql container 접속하여 로그인 한 후 wordpress db에 customer 테이블을 생성해 본다. + +
+ +### 과제 2 + +mysql container 접속하여 로그인 한 후 wordpress db에 +아래 테이블 script를 로컬에 저장된 화일을 사용하여 test 테이블을 생성해 본다. + + https://github.com/shclub/edu1/blob/master/test.sql 화일을 다운 받는다. + + + - TIP : 화일 이동 방법은 cp 명령어 사용. + + 호스트 -> 컨테이너 + ```bash + docker cp [host 파일경로] [container name]:[container 내부 경로] + ``` + 컨테이너 -> 호스트 + + ```bash + docker cp [container name]:[container 내부 경로] [host 파일경로] + ``` + +
+ +### 과제 3 + +금일 실습한 Dockerfile과 docker-compose.yml 화일을 git 명령어를 사용하여 edu2에 push 한다. + +
+ +### 과제 4 + +docker 컨테이너 GUI 관리 툴인 portainer를 설치하고 웹에서 접속하여 + 모니터링한다. + - url 참고 : https://docs.portainer.io/v/ce-2.11/start/install/server/docker/linux + - 웹 포트는 40005로 expose 한다 ( https 9443 포트 변경 필요 ). + - 웹브라우저 접속은 https://(본인VM Public IP):40005 + admin 비밀번호 신규로 생성 (8자리 이상) 한다. \ No newline at end of file diff --git a/chapter3.md b/chapter3.md new file mode 100644 index 0000000..a29798b --- /dev/null +++ b/chapter3.md @@ -0,0 +1,657 @@ +# Chapter 3 + + +kubernetes 는 FlyingCube 2.0 ( OKD 4.7 ) 로 실습을 진행하다. + +1. kubernetes 설명 + +2. Kubernetes 의 API 서버 보안 ( Service Account ) + +3. Kubernetes 의 Downward API + +참고 : https://subicura.com/k8s/ + + + +
+ +## kubernetes + +### 쿠버네티스 시작하기 + +개발 환경에서 당연하게 사용해왔던 쿠버네티스에 대해 이해하고, 왜 쿠버네티스를 사용하는지 알아보자. + +
+ +개요 +- 컨테이너 오케스트레이션의 개념과 사용하는 이유 그리고 특징에 대해 이해한다. + +소개 +- 쿠버네티스는 컨테이너 오케스트레이션 툴의 한 종류이며 엄청난 인기로 사실상 표준으로 사용된다. +- 컨테이너 오케스트레이션은 복잡한 컨테이너 환경을 효과적으로 관리하기 위한 도구이다. + +배경 +- 서버의 상태를 편하게 관리하기 위한 노력으로 도커 컨테이너가 등장했다. +- 그러나 관리하는 서버 컨테이너 수가 점점 증가하며 관리가 힘들다는 문제가 생겼다. +- 그래서 등장한 것이 컨테이너 오케스트레이션이다. + +컨테이너의 특징 + +- 가상머신과 비교하여 컨테이너 생성이 쉽고 효율적 +- 컨테이너 이미지를 이용한 배포와 롤백이 간단 +- 언어나 프레임워크에 상관없이 애플리케이션을 동일한 방식으로 관리 +- 개발, 테스팅, 운영 환경을 물론 로컬 피시와 클라우드까지 동일한 환경을 구축 +- 특정 클라우드 벤더에 종속적이지 않음 + + +
+ +### 컨테이너 오케스트레이션 + +
+ +컨테이너 오케스트레이션을 사용하지 않는다면 + +- 배포(Deployment) + + + + - 각 서버의 ip를 찾고 각 서버에 ssh로 접속해서 docker 명령어로 컨테이너를 실행 및 종료하는 수고가 든다. + - 만약 새로운 컨테이너를 실행하려면 빈 서버(여유있는)에 실행 하는것이 리소스 절약을 위해 좋으나, 이를 확인하기 위한 모니터링 툴이 없으면 빈 서버를 일일히 찾기도 힘들다. + - 서버를 배포할 때(version upgrade 또는 rollback) 모든 서버를 한번에 배포하는 방법이 필요하다. + +
+ +- 서비스 검색(Service Discovery) + + + + - 보통의 구조라면 프록시 서버가 있고 로드밸런서를 통해 서버에 적절히 부하를 분산한다. + - 그러나 로드밸런서와 서버의 ip 설정과 같은 부분이 관리자가 직접 관리해야하는 포인트였다. + - 마이크로서비스 환경이 유행처럼 등장하며 서버가 점점 많아지고 서버의 ip가 업데이트로 변경되고 하면서 관리자가 이를 모두 관리하는 것은 쉽지 않았다. + +
+ +- 서비스 노출(Gateway) + + + + - NginX와 같이 외부에 노출된 프록시 서버를 두고, 프록시 서버로 들어오는 host 요청에 따라 내부 컨테이너(서버)에 연결하는데 이 과정에 자동화가 필요했다. + +
+ +- 서비스 이상과 부하 모니터링 + + + + - 갑자기 컨테이너가 죽은 경우에 이전에는 일일히 로그 확인해서 다시 서버를 띄워야 했다. + - 같은 서버 컨테이너가 3개 돌다가 하나의 컨테이너가 죽으면 남은 2개의 서버에 부하가 생긴다. + - 서버가 죽지는 않았는데 트래픽이 많아지면 부하가 걸려 느려졌다. + - 트래픽에 따라 적절하게 서버를 늘려야 함 + - 위와 같은 상황으로 자동화가 필요했다. + + +
+ +컨테이너 오케스트레이션 + +- 위와같은 문제로 많은 컨테이너를 효율적으로 관리하기 위한 기술이 컨테이너 오케스트레이션이다. +- 컨테이너 오케스트레이션 복잡한 컨테이너 환경을 효과적으로 관리하기 위한 도구이다. + +
+ +컨테이너 오케스트레이션 특징 + +- 클러스터(Cluster) + + + + - 중앙 제어 + - 이전에는 서로 다른 노드의 CPU와 RAM 상태를 각각 관리했었다. + - 그러나 노드 수가 증가하면 힘들기 때문에, 컨테이너 오케스트레이션에서는 합쳐서 추상화하여 클러스트 단위로 관리한다. + - 클러스터 하나하나의 노드에 ssh로 직접 접속하기 힘들기때문에 프록시처럼 앞에 마스터 서버를 두고 마스터서버가 각 노드에 알아서 명령을 보낸다. + + - 네트워킹 + - 클러스터 내 노드끼리는 서로 통신이 잘되어야 한다. + - 노드 스케일 + - 노드 스케일이 커지더라도 잘 돌아가기 위해서는 정교한 설계가 필요하다. + +
+ +- 상태 관리(State) + + + + - 트래픽이 증가해 서버를 새로 늘리거나, 하나의 서버에 장애가 발생했을 때 감지하고 자동으로 서버를 늘려준다. + - 오토 스케일링 + +
+ +- 배포 관리(Scheduling) + + + + - 자원이 여유가 있는 서버에 알아서 적절하게 띄워준다. + +
+ +- 배포 버전관리(Rollout & Rollback) + + + + - 전체 컨테이너에 대한 롤아웃과 롤백을 중앙에서 관리한다. + +
+ +- 서비스 등록 및 조회(Service Discovery) + + + + - 새로 등록된 서비스 ip나 변경된 ip를 자동으로 관리해줘서 관리자가 하나하나 수정할필요가 없다. + + +
+ +- 볼륨 스토리지(Volume) + + + + - 각 서버에 필요한 스토리지(AWS EBS, GCE 등)를 설정으로 연결할 수 있다. + - AWS에서 EC2에 스토리지 일일히 하나하나 붙이고 그럴 필요가 없다는 말이다. + +
+ +왜 쿠버네티스인가 + +- 컨테이너 관리도구가 많이 생기고 했으나, 쿠버네티스가 표준처럼 등장했다. +- 오픈소스 + + - 컨테이너를 쉽고 빠르게 배포/확장하고 관리를 자동화해주는 오픈소스 플랫폼 + - 구글에서 만듬 (구글은 1주일에 20억개 컨테이너 생성한다.) + +- 엄청난 인기 + - 점유율이 높고 그렇기에 라이브러리 또는 레퍼런스가 많다. + +- 무한한 확장성 + - 쿠버네티스 위에서 머신러닝, CI/CD, 서비스. 서버리스 등 다양한 서비스가 동작 + - 쿠버네티스만 설치되어 있으면 거기에 서비스를 올리기 쉬움 + +- 사실상 표준(de facto) + - 많은 오케스트레이션이 있지만 사실상 표준이 되어가고 있음 + - 도커도 자체 오케스트레이션이 있지만 쿠버네티스의 인기로 인해 어쩔수없이 쿠버네티스 지원 + - AWS(Elastic Kubernetes Service), Azure(Azure Kubernetes Service), Google(Google Kubernetes Engine)와 같이 대표적인 클라우드 기업들이 쿠버네티스를 매니지드 서비스로 제공하고 있음 + +
+ + +### kubernetes API 서버 보안 + +
+ +쿠버네티스에서 API 서버 보안은 왜 필요할까? + +쿠버네티스에서는 이론적으로 파드 외부 또는 내부에서 API 서버로 적절한 요청을 하면 어떤 리소스던 생성, 삭제, 수정, 조회가 가능하다. + +그런데 만약 개발자의 코딩 실수로 어떤 파드에서 아무 관련이 없는 다른 파드를 삭제해버릴 수 있다면 큰 문제가 될 것이다. + +그렇기 때문에 사용자 또는 파드에게 적절하게 권한을 부여하는 기능은 보안과 안정적인 운영을 위해 필수적이다. + +회사에서 여러개의 팀이 하나의 공용 클러스터를 함께 사용하는 멀티테넌트 환경에서는 이러한 권한의 분리가 더욱 중요하다. + +쿠버네티스 클러스터는 API 서버가 사용자나 Pod 의 요청을 받을 때 명시적으로 설정된 권한만 허용하고, 그 이외의 모든 권한은 허용하지 않도록 동작한다. + +
+ +#### Service Account 란? + +
+ +서비스 어카운트(Service Account) 는 Kubernetes 의 파드에서 API 서버에 요청을 보냈을 때 이 "파드"를 식별하기 위한 리소스다. (사용자를 식별하는데 사용되지는 않는다) + +파드에서 API 서버에 요청을 보내면 이 파드의 정체가 무엇인지 알아야 어떤 권한을 가지고 있는지도 알 수 있고, + +이를 기반으로 파드의 요청이 권한에 맞는지를 확인하여 요청을 처리해줄지 말지를 결정할 것이다. + +실제로 권한을 정의하고, 설정하는 부분은 이후에 설명할 Role, ClusterRole, RoleBinding, ClusterRoleBinding 의 역할이다. + +
+ +#### ServiceAccount 의 특징 + +
+ +모든 파드는 무조건 하나의 ServiceAccount 와 매핑이 되어야 실행될 수가 있다. + +그런데 ServiceAccount 를 만들지 않고, 파드의 매니페스트에 ServiceAccount 를 명시적으로 적어주지 않아도 파드가 잘 생성이 되고 실행 되는 것을 보고 의아할 수도 있다. + +사실 이것은, 쿠버네티스의 ServiceAccount Controller 가 모든 네임스페이스에 default 라는 이름의 서비스어카운트가 있도록 자동 생성해주며, + +ServiceAccount `Admission Controller` 가 파드의 매니페스트에 명시적으로 서비스어카운트를 정의하지 않으면 default 서비스어카운트를 매핑해주기 때문에 가능한것이다. + +뿐만 아니라, 서비스어카운트는 mountable secrets 에 지정한 시크릿만 파드에 마운트할 수 있도록 강제하는 기능과, + +Image pull secrets 기능을 통해 프라이빗 이미지 레지스트리에서 이미지를 가져올 수 있도록 하기 위한 시크릿을 이 서비스어카운트를 사용하는 파드에 자동으로 마운트시켜주는 기능도 가지고 있는데 + +image pull secrets 기능도 ServiceAccount Admission Controller 가 수행한다. + +
+ +#### ServiceAccount 의 동작 방식 + +
+ +kubectl create sa 명령어로 서비스어카운트를 생성할 수 있다. + + +`Token Controller` 는 서비스어카운트가 생성될 때마다 자동으로 kubernetes.io/service-account-token 타입의 Secret 을 생성하여 매핑시켜준다. + +```bash +root@jakelee:~# kubectl get sa +NAME SECRETS AGE +default 1 18d +root@jakelee:~# kubectl get secret +NAME TYPE DATA AGE +default-token-p9fpr kubernetes.io/service-account-token 3 18d +root@jakelee:~# kubectl describe secret default-token-p9fpr +Name: default-token-p9fpr +Namespace: default +Labels: +Annotations: kubernetes.io/service-account.name: default + kubernetes.io/service-account.uid: ef9e4103-6663-4fcb-a12f-e2626d7e9666 + +Type: kubernetes.io/service-account-token + +Data +==== +token: eyJhbGciOiJSUzI1NiIsImtpZCI6ImhvbzBnMGhOX1VBMFp6MVN4ejFoX0RoVEtBX25lZUNkX291d3BnLUNWWVEifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tcDlmcHIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImVmOWU0MTAzLTY2NjMtNGZjYi1hMTJmLWUyNjI2ZDdlOTY2NiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.wHfW2CGCePikcfSumoM9GvUIQS_8gI_wqKRnz9XzRFJ7rBl2iZNM7h47rPhHcA-uR61G6C6mzFHzb0zVYfo_PQAuddYF1PB3FZ9DmlylX3J1ne2KBQhh_f88FXmRCQZbiK5DS_GiR1Ys2UWzykLQFXtHDrQ7n_oy3Bq3poi4lDObg_TIH2rSyrhADebDqRXHOUZ5GGNV3Y7qwTvl9hFhbPT6Z8VO0mGgpHvv52XmNzHORUhwZRsMBLlMh19DNVTizvRlhemTZJMM71d8wJ9KG9rFhDwodWzuWgCYNxklWDvhDCsuJSj1QHei-9QSdqy2YTp5Qddcux7nMgyufQZT9Q +ca.crt: 570 bytes +namespace: 7 bytes +``` + + +Token Controller 에 의해 생성된 Secret 에는 아래와 같은 3가지 데이터가 base64 로 인코딩되어 들어있다. + +- ca.crt - API 서버와 통신 시, SSL 인증을 위한 증명서 +- token - 서비스어카운트 이름, Secret 이름 등의 정보에 서명한 JWT. + API 서버에 요청시 Bearer 토큰으로 사용됨 +- namespace - 네임스페이스 + +파드 내 애플리케이션은 위의 데이터를 사용하여 API 서버와 통신한다. + +API 서버는 요청의 Authorization 헤더에 있는 Bearer token 을 디코딩하여 어느 서비스어카운트를 사용해 보낸 요청인지 식별하게 된다. + +
+ +#### RBAC 란? + +
+ +어떤 사람, 혹은 파드가 API 서버에 요청을 하면 API 서버는 인증(Authentication)과 인가(Authorization)를 수행한다. + +인증은 접근 가능 여부를 확인하는 것이고, 인가는 접근 가능한 요청에 대해 요청된 자원에 접근할 수 있는지를 확인하는 것이다. + +RBAC(Role-Based Access Control) 는 API 서버가 인가를 수행하는 여러 방법 중 하나다. + +쿠버네티스는 다음과 같은 인가 방식을 제공한다. + +- Node + - Kubelet 에 의한 요청에 대한 인가를 위한 방식 +- ABAC(Attribute-Based Access Control) + - 리소스의 속성에 따라 인가를 하는 방식 +- RBAC + - Role 을 기반으로 인가를 하는 방식 +- Webhook + - 외부 API 를 통해 인가를 하는 방식 + +이 중에서 RBAC가 표준이며, kubernetes 1.8.0 부터는 대부분의 클러스터에서 기본적으로 사용하는 방식이다. + +RBAC 는 `특정 주체(subject) 가 특정 대상(url, resource 타입, 혹은 특정 resource) 에 대해 특정 행위(verb)` 를 할 수 있는지를 지정하는 방식이다. + +
+ +#### Role 과 RoleBinding + + +
+ +어떤 사람, 혹은 파드가 API 서버에 요청을 하면 API 서버는 인증 + +Role 은 대상(resource 등) 과 행위(verb) 를 지정하며, RoleBinding 은 주체(subject) 를 지정한다. + +여기서 주체는 3가지(User, Group, ServiceAccount) 중 한가지가 된다. + +대상은 보통 resource 의 타입을 정하는데, resourceName 으로 특정 리소스를 지정할 수도 있다. + +이후에 설명할 ClusterRole 에서는 리소스가 아닌 URL 을 지정할 수도 있다. /healthz 와 같이 특정 리소스에 대한 요청이 아닌 경우도 있기 때문이다. + +행위는 아래 표와같이 API 요청에 사용된 HTTP 메서드에 따라 특정 행위에 매핑되는데, + + + + +행위에 대한 대상이 리소스라면 행위를 verb 로 적어주고, URL 이라면 HTTP 메소드로 적어준다. + +이름 그대로 Role 은 역할이고, RoleBinding 은 이러한 역할을, 역할을 수행하는 주체에 연결시켜 주는 것이다. + +
+ +#### Role 과 RoleBinding 의 특징 + +
+ +Role 과 RoleBinding 은 특정 네임스페이스에 종속된 개념이다. 그렇기 때문에 RoleBinding 은 다른 네임스페이스의 Role 을 바인딩해줄 수는 없다. + +하지만, RoleBinding 이 같은 네임스페이스의 Role 을 다른 네임스페이스의 subject 에게 바인딩해 줄 수는 있다. + +그래서 RoleBinding 에 subject 들을 명시할 때는 name 과 namespace, 그리고 kind(user/group/serviceaccount) 를 함께 명시한다. + +하나의 Role 은 여러개의 RoleBinding 에 의해 바인드될 수 있고, 하나의 RoleBinding 은 하나의 Role 만 참조할 수 있다. + +즉, `Role 과 RoleBinding 은 일대다(one-to-many)` 관계다. + +반면 하나의 RoleBinding 은 하나의 Role 을 여러 주체에 연결시켜 줄 수 있고, 하나의 주체는 여러개의 RoleBinding 에 의해 권한이 부여될 수 있다. + +즉, `RoleBinding 과 Subject(ServiceAccount 등) 는 다대다(many-to-many)` 관계다. + +
+ +#### Role 과 RoleBinding 만들기 + +
+ +Role 과 RoleBinidng 을 만드는 방법은 크게 두가지가 있다. + +하나는 매니페스트를 통해 만드는 방법이고, 나머지 하나는 kubectl create 명령어를 통해 만드는 방법이다. + +다음과 같이 YAML 파일을 작성하지 않고도 직접 verb, resource, role, serviceaccount 등을 인자로 주어 Role 과 RoleBinding 을 생성할 수 있다. + +먼저 아래 소스를 사용하여 role을 생성합니다. + +```bash +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: default + name: service-reader +rules: + - apiGroups: [""] + verbs: ["get", "list"] + resources: ["services"] +``` + +### kuKubernetes 의 Downward API + +
+ +#### Downward API 란? + +
+ +애플리케이션이 실행되기 전에 이미 알고있는 속성이나 설정 값들은 ConfigMap 이나 Secret 으로 파드에 전달할 수 있지만, + +파드의 이름, 파드의 IP, 파드가 실행되는 노드의 이름 등 실제로 파드가 생성 및 실행이 되기전에는 알 수 없는 속성들도 존재한다. + +물론 파드의 레이블이나 어노테이션과 같은 일부 속성들은 파드 생성 이전에도 알 수 있지만, + +파드 내에서 정보를 사용하고 싶다는 이유로 이미 설정되어 있는 속성을 ConfigMap 등을 통해 중복하여 정의하고 싶지는 않을 것이다. + +이런 속성들을 컨테이너에서 실행 중인 애플리케이션에서 알아내려면 어떻게 해야할까? + +이 때 사용되는 것이 Downward API 이다. + +Downward API 는 단순히 환경변수, 또는 파일(downwardAPI 볼륨을 통해) 로 위와 같은 속성들을 컨테이너에서 손쉽게 사용할 수 있도록 하는 기능일 뿐이다. + +Downward API 를 통해 전달할 수 있는 정보는 다음과 같다. + +- 파드의 이름 +- 파드의 IP 주소 +- 파드가 속한 네임스페이스 +- 파드가 실행중인 노드의 이름 +- 파드가 실행 중인 서비스 어카운트 이름 +- 각 컨테이너의 CPU와 메모리 request +- 각 컨테이너의 CPU와 메모리 limit +- 파드의 label +- 파드의 annotation + +k8s 에서는 파드가 API server 와 통신할 수 있도록 하기 위해 +각 파드마다 기본적으로 Default token 시크릿 볼륨을 만들어 + +파드 내 컨테이너의 /var/run/secrets/kubernetes.io/serviceaccount/에 마운트해 주는데, + +이 곳에 namespace 라는 파일에 네임스페이스가 적혀있기 때문이다. + +```bash +root@jakelee:~# kubectl get po +NAME READY STATUS RESTARTS AGE +flask-edu4-app-74788b6479-nmcvv 1/1 Running 0 16d +flask-edu4-app-74788b6479-rlght 1/1 Running 0 16d +hpa-example-deploy-59bf97fcc6-6nxjs 1/1 Running 0 16d +inspekt-deployment-c8d9f5dcf-2slpx 1/1 Running 0 11d +mynginx-69d586ff67-bmh6m 1/1 Running 0 10d +web2-5d47994f45-dmrwr 1/1 Running 0 9d +pod-test-app 1/1 Running 0 6d20h +root@jakelee:~# kubectl exec -it pod-test-app sh +kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. +# ls /var/run/secrets/kubernetes.io/serviceaccount/ +ca.crt namespace token +# cat /var/run/secrets/kubernetes.io/serviceaccount/namespace +default +``` + +
+ +#### 환경 변수로 전달하기 vs 볼륨으로 전달하기 + +
+ +Downward API 를 통해 데이터를 전달하기 위한 방법으로는 + +환경 변수를 통한 방법과 볼륨을 통한 방법, 이렇게 크게 두가지가 있다. + +대부분의 경우 환경변수를 통한 방법과 볼륨을 통한 방법 중 어떤 방법을 사용해도 크게 문제가 없지만 + +약간의 차이점이 있다. 우선 일부 정보들은 둘 중 한가지 방법으로만 얻을 수 있다. + +예를 들어 Pod 의 label 과 annotation 은 downwardAPI 볼륨을 통해서만 전달할 수 있다. + +그 이유는, Pod 의 label 과 annotation 은 Pod 가 실행되는 동안 수정될 수가 있는데, + +이 때 Pod 가 변경된 데이터를 볼 수 있도록 해야 한다. + +파드가 실행중인 노드의 이름과 IP 는 환경 변수를 통한 방법으로만 얻을 수 있다. + +
+ +#### 환경변수로 전달하기 + +
+ + +vi에디터로 downward-env.yaml 화일을 만들어 보자. + +```bash +root@jakelee:~# vi downward-env.yaml +``` + +아래 소스를 사용한다. + + +```bash +apiVersion: v1 +kind: Pod +metadata: + name: downward-env +spec: + containers: + - name: main + image: busybox + command: ["sleep", "99999"] + resources: + requests: + cpu: 15m + memory: 100Ki + limits: + cpu: 100m + memory: 20Mi + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: CONTAINER_CPU_REQUEST_MILLICORES + valueFrom: + resourceFieldRef: + resource: requests.cpu + divisor: 1m + - name: CONTAINER_MEMORY_LIMIT_KIBIBYTES + valueFrom: + resourceFieldRef: + resource: limits.memory + divisor: 1Ki +``` + +pod를 생성한다. + +```bash +root@jakelee:~# kubectl apply -f downward-env.yaml +pod/downward-env created +``` + +```bash +root@jakelee:~# kubectl get po +NAME READY STATUS RESTARTS AGE +pod-test-app 1/1 Running 0 6d20h +downward-env 1/1 Running 0 12s +``` + +pod가 생성이 되면 환경 변수를 조회해 본다. + +기본 환경 변수에 POD_NAME , POD_NAMESPACE , POD_IP , POD_NAME이 추가 된 것을 확인 할 수 있다. + +```bash +root@jakelee:~# kubectl exec downward-env env +kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +HOSTNAME=downward-env +SERVICE_ACCOUNT=default +CONTAINER_CPU_REQUEST_MILLICORES=15 +CONTAINER_MEMORY_LIMIT_KIBIBYTES=20480 +POD_NAME=downward-env +POD_NAMESPACE=default +POD_IP=10.42.0.130 +NODE_NAME=jakelee +``` + + + +
+ +#### 볼륨으로 전달하기 + +
+ +vi에디터로 downward-volume.yaml 화일을 만들어 보자. + +```bash +root@jakelee:~# vi downward-volume.yaml +``` + +아래 소스를 사용한다. + + +```bash +apiVersion: v1 +kind: Pod +metadata: + name: downward-volume + labels: + foo: bar + annotations: + key1: value1 + key2: | + multi + line + value +spec: + containers: + - name: main + image: busybox + command: ["sleep", "9999999"] + resources: + requests: + cpu: 15m + memory: 100Ki + limits: + cpu: 100m + memory: 40Mi + volumeMounts: + - name: downward + mountPath: /etc/downward + volumes: + - name: downward + downwardAPI: + items: + - path: "podName" + fieldRef: + fieldPath: metadata.name + - path: "podNamespace" + fieldRef: + fieldPath: metadata.namespace + - path: "labels" + fieldRef: + fieldPath: metadata.labels + - path: "annotations" + fieldRef: + fieldPath: metadata.annotations + - path: "containerCpuRequestMilliCores" + resourceFieldRef: + containerName: main + resource: requests.cpu + divisor: 1m + - path: "containerMemoryLimitBytes" + resourceFieldRef: + containerName: main + resource: limits.memory + divisor: 1 +``` + +pod가 생성이 되면 volume을 조회해 본다. + + +```bash +root@jakelee:~# kubectl get po +NAME READY STATUS RESTARTS AGE +pod-test-app 1/1 Running 0 6d20h +downward-env 1/1 Running 0 14m +downward-volume 1/1 Running 0 68s +root@jakelee:~# kubectl exec downward-volume ls /etc/downward +kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. +annotations +containerCpuRequestMilliCores +containerMemoryLimitBytes +labels +podName +podNamespace +root@jakelee:~# kubectl exec downward-volume cat /etc/downward/podName +kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. +downward-volume +``` + +
+ diff --git a/chapter4.md b/chapter4.md new file mode 100644 index 0000000..2c3fe96 --- /dev/null +++ b/chapter4.md @@ -0,0 +1,285 @@ + +# Chapter 4 + + +ArgoCD는 GitOps를 구현하기 위한 컨테이너에 최적화된 CD 툴 + +1. GitOps 란 : https://coffeewhale.com/kubernetes/gitops/argocd/2020/02/10/gitops-argocd/ + +2. ArgoCD 설치 및 기능 설명 + +3. Github에 배포 설정 + +4. 배포 실습 ( Blue/Green , Canary , Rollback ) + + +
+ +## GitOps + +### GitOps 개요 + +개발자와 운영자의 소통, 협업, 통합을 강조하는 DevOps는 많이들 들어보셨을 겁니다. + +GitOps는 DevOps의 실천 방법 중 하나로 애플리케이션의 배포와 운영에 관련된 모든 요소들을 Git에서 관리(Operation) 한다는 뜻입니다. + + + +아주 간단하게 말해서 GitOps는 Kubernetes Manifest파일을 Git에서 관리하고, 배포할때에도 Git에 저장된 Manifest로 클러스터에 배포하는 일련의 과정들을 의미합니다. + +
+ +GitOps 원칙 + +- 모든 시스템은 선언적으로 선언되어야 함 +“선언적(declarative)”이라 함은 명령들의 집합이 아니라 사실(fact)들의 집합으로 구성이 되었음을 보장한다는 의미입니다. +쿠버네티스의 manifest들은 모두 선언적으로 작성되었고 이를 Git으로 관리한다면 versioning과 같은 Git의 장점과 더불어, SSOT(single source of truth)를 소유하게 됩니다. +- 시스템의 상태는 Git의 버전을 따라감 +Git에 저장된 쿠버네티스 manifest를 기준으로 시스템에 배포되기 때문에 이전 버전의 시스템을 배포하고싶으면 git revert와 같은 명령어를 사용하면 됩니다. +- 승인된 변화는 자동으로 시스템에 적용됨 +한 번 선언된 manifest가 Git에 등록되고 관리되기 시작하면 변화(코드수정 등)가 발생할때마다 자동으로 시스템에 적용되어야 하며, 클러스터에 배포할때마다 자격증명은 필요하지 않아야 합니다. +- 배포에 실패하면 이를 사용자에게 경고해야 함 +시스템 상태가 선언되고 버전 제어 하에 유지되었을 때 배포가 실패하게되면 사용자에게 경고할 수 있는 시스템을 마련해야합니다. + +
+ +GitOps Repository + +GitOps Pipeline을 설계할때에는 Git Repository를 최소 두개이상 사용하는 것을 권장합니다. + + + + +- App Repo : App 소스코드와, 배포를 위한 Manifest 파일 +- 배포 환경 구성용 Repo : 배포 환경에 대한 모든 Manifest (모니터링, 서비스, MQ 등)들이 어떤 버전으로 어떻게 구성되어있는지 포함 + + +
+ +GitOps 배포 전략 + +두가지 방법이 있습니다. + +- Push Type +Git Repo가 변경되었을 때 파이프라인을 실행시키는 구조입니다. + + + + 배포 환경의 개수에 영향을 받지 않으며 접속 정보를 추가하거나 수정하는 것만으로도 간단하게 배포 환경을 추가하거나 변경할 수 있습니다. + 아키텍처가 쉬워 많은 곳에서 사용하고 있으나, 보안정보가 외부로 노출될 수 있다는 단점이 있습니다. + +- Pull Type +배포하려는 클러스터에 위치한 별도의 오퍼레이터가 배포역할을 대신합니다. + + + + 해당 오퍼레이터는 Git Repo의 Manifest와 배포환경을 지속적으로 비교하다가 차이가 발생할 경우, Git Repo의 Manifest를 기준으로 클러스터를 유지시켜 줍니다. + + 또한 Push Type과 달리 오퍼레이터가 App과 동일한 환경에서 동작중이므로 보안 정보가 외부에 노출되지 않고 실행할 수 있습니다. + +
+ + +### ArgoCD 둘러보기 + +
+ +ArgoCD를 설치하여 로그인하면 가장 먼저 볼 수 있는 화면은 아래와 같습니다. + +지금까지 생성한 배포 App의 리스트를 보여주는 화면입니다. 새로운 배포를 관장하는 App을 생성해 보기 위해 New App 버튼을 눌러보겠습니다. + + + +새로운 배포을 책임지는 App을 생성하는 화면입니다. + + + +- Application Name: App의 이름을 적습니다. +- Project: 프로젝트를 선택하는 필드입니다. 쿠버네티스의 namespace와 비슷한 개념으로 여러 App을 논리적인 project로 구분하여 관리할 수 있습니다. +- Sync Policy: Git 저장소의 변경 사항을 어떻게 sync할지 결정합니다. Auto는 자동으로 Git 저장소의 변경사항을 운영에 반영하고 Manual은 사용자가 버튼 클릭을 통해 직접 운영 반영을 해줘야 합니다. +- Repository URL: ArgoCD가 바라볼 Git 저장소를 의미합니다. +- Revision: Git의 어떤 revision (HEAD, master branch 등)을 바라 볼지 결정합니다. +- Path: Git 저장소에서 어떤 디렉토리를 바라 볼지 결정합니다. (dot(.)인 경우 root path를, 디렉토리 이름을 적으면 해당 디렉토리의 배포 정의서만 tracking 합니다.) +- Cluster: 쿠버네티스의 어느 클러스터에 배포할지를 결정합니다. +- Namespace: 쿠버네티스 클러스터의 어느 네임스페이스에 배포할지를 결정합니다. +- Directory Recurse: path아래의 디렉토리를 재귀적으로 모니터링하여 변경 사항을 반영합니다. + +
+ +아래의 깃헙 레포지토리를 예시로 배포해 보겠습니다. 간단하게 nginx 컨테이너를 생성하고 서비스를 붙여주는 앱입니다. + +GitOps repository 예시: https://github.com/shclub/edu5.git + +본인의 github에서 위 repository를 fork 합니다. + +아래 처럼 deployment.yaml , service.yaml , ingress.yaml이 생성된걸 확인 할 수 있습니다. + +ingress.yaml 화일의 host 정보는 본인 VM Public IP로 변경 합니다. + +```bash +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mynginx +spec: + replicas: 1 + selector: + matchLabels: + run: mynginx + template: + metadata: + labels: + run: mynginx + spec: + containers: + - image: nginx + name: mynginx + ports: + - containerPort: 80 +``` + + +```bash +apiVersion: v1 +kind: Service +metadata: + name: mynginx +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + run: mynginx +``` + +```bash +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: mynginx-traefik-ingress + annotations: + ingress.kubernetes.io/rewrite-target: "/" + kubernetes.io/ingress.class: traefik +spec: + rules: + - host: mynginx.210.106.105.165.sslip.io + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: mynginx + port: + number: 80 +``` + +url은 본인의 url로 설정한다. + +- Application Name: caravan +- Project: default +- Sync Policy: manual +- Repository URL: https://github.com/shclub/edu5.git +- Revision: HEAD +- Path: . +- Cluster: in-cluster +- Namespace: default +- Directory Recurse: Unchecked + +
+ +우리는 아래와 같이 설정을 한다. + + + + + + +위와 같이 값을 설정해주고 `Create` 버튼을 클릭합니다. + +`SYNC` 버튼을 눌러 ArgoCD가 변경 사항을 확인하여 단일원천의 진실에 따라 운영 환경을 그에 맞게 변경하도록 하겠습니다. + + + +App을 클릭하면 아래와 같이 Ingress, Service 리소스와 nginx pod가 생성된 것을 UI로 확인하실 수 있습니다. + + + +파란색 아이콘이 보이면 정상적으로 수행이 된것 있고 mynginx pod 가 정상적으로 생성 되었는지 확인합니다. + +```bash +root@jakelee:~# kubectl get po +NAME READY STATUS RESTARTS AGE +flask-edu4-app-74788b6479-qgs2j 1/1 Running 0 6d21h +flask-edu4-app-74788b6479-l7gkx 1/1 Running 0 6d21h +flask-edu4-app-74788b6479-nmcvv 1/1 Running 0 6d21h +flask-edu4-app-74788b6479-f2kcp 1/1 Running 0 6d21h +flask-edu4-app-74788b6479-rlght 1/1 Running 0 6d21h +hpa-example-deploy-59bf97fcc6-6nxjs 1/1 Running 0 6d1h +inspekt-deployment-c8d9f5dcf-2slpx 1/1 Running 0 23h +mynginx-69d586ff67-bmh6m 1/1 Running 0 6m23s +``` + +Ingress를 설정 했기 때문에 web browser 에서 도메인으로 접속해봅니다. +정상이면 아래와 같이 nginx welcome 화면이 보입니다. + + + +
+ +앞에 App을 설정할때 sync-policy를 manual 설정하였습니다. + +아래에 Auto-Sync 버튼을 활성화하게 되면 Automatic이 되어 매번 사람이 직접 변경사항을 ArgoCD에게 알릴 필요 없이 ArgoCD가 주기적으로 Git 레포지터리의 변경사항을 확인하여 변경된 부분을 적용하게 됩니다. + +이때 두가지 옵션을 추가적으로 줄 수 있습니다. + +- Prune Resources: 변경 사항에 따라 리소스를 업데이터할 때, 기존의 리소스를 삭제하고 새로운 리소스를 생성합니다. Job 리소스처럼 매번 새로운 작업을 실행해야 하는 경우 이 옵션을 사용합니다. + +- Self Heal: 해당 옵션을 활성화 시키면 ArgoCD가 지속적으로 git repository의 설정값과 운영 환경의 값의 싱크를 맞출려고 합니다. 기본적으로 5초마다 계속해서 sync를 시도하게 됩니다. (default timeout) + +해당 예시에서는 Auto-sync만 활성화 시켜보겠습니다. 그런 다음, 이제 git repository의 deployment replica 값을 2로 고쳐서 ArgoCD가 자동으로 변경한 값을 운영 환경에 반영하는지 확인해 보겠습니다. + + + +AppDetail을 클릭하면 하단에 enable auto sync 버튼을 클릭합니다. + + + +신규로 pod가 하나 생성되어 2개의 pod가 존재하는 것을 확인 할수 있습니다. + + + +traffic 흐름을 볼수 도 있고 + + + +각 node의 resource 들을 볼 수 있고 pod의 리소스도 확인 가능 하다. + + + + +기본적으로 swagger를 제공하고 있어 ArgoCD 의 API를 사용 할 수 있다. +- 사용법 : http:// < 본인의 argocd URL > / swagger-ui + + + + +
+ +기본 사용법 + - https://argo-cd.readthedocs.io/en/stable/getting_started/#creating-apps-via-ui + +
+ +추가 배포 관련 Hands-on은 아래 문서를 참고 한다. + +- 문서를 참고한다. [ArgoCD Hands-On ](./argocd_hands_on.md) + +
+ + + + + + diff --git a/k8s_basic_hands_on.md b/k8s_basic_hands_on.md new file mode 100644 index 0000000..1e4b674 --- /dev/null +++ b/k8s_basic_hands_on.md @@ -0,0 +1,1667 @@ +# k8s Basic Hands-on + +kubernetes에서 kubectl를 사용하여 cli 실습을 한다. + +1. 실습 전체 개요 + +2. Kubeconfig 설정 : kubectl 설치 ( 윈도우 / Mac ) + +3. Kubectl 활용 + +4. kubernetes 리소스 ( Pod , Service , Deployment 생성 및 삭제) + +5. 배포 ( Rolling Update / Rollback ) + +6. Serivce Expose ( Ingress ) + +7. 참고 사이트 + - podman 사용 : https://github.com/chhanz/kubernetes-hands-on-lab + - https://github.com/subicura/workshop-k8s-basic/tree/master/guide + + +
+ +## 실습 전체 개요 + + +### Deployment, Service, Ingress/Route 흐름 설명 + + + + +
+ +Ingress/Route : HTTP 나 HTTPS 통신을 클러스터 내부의 서비스에 연결해 주는 도구. +쉽게 말해 가정집의 공유기와 비슷한 역할을 한다. +Deployment(pod) 는 Service 와 연결된다고 선술한 바 있다. + +Ingress 는 아래 이미지와 같이 Service 와 연결해주면 된다. + + +- Deployment 정의 : Deployment는 메타데이터 및 pod 리플리카 개수, 컨테이너 이미지, 이미지 포트 등을 정의한다. + + +- Service 정의 : Service는 아래와 같이 어노테이션 및 서비스 포트 및 타깃 포트 등을 정의한다. + + +- ingress/Route 정의 : 어노테이션 및 ingress의 서비스 name과 port를 정의한다. + +
+ +Deployment 와 Service 그리고 Ingress의 관계가 간단하게 정리된 그림 + + + +
+ +위의 예시를 토대로 Deployment와 Service 그리고 Ingress의 관계를 Flow로 표현한 그림 + + + +
+ +## Kubeconfig 설정 : kubectl 설치 ( 윈도우 / Mac ) + +### kubectl 설치 ( https://kubernetes.io/ko/docs/tasks/tools/ ) + +
+ +GUI IDE인 lens 대신 kubectl cli를 통해 실습을 하기 위해 로컬 PC에 +kubectl 을 설치 한다. + + +- Windows + 아래사이트에서 최신 버전을 다운로드 받는다. +https://kubernetes.io/ko/docs/tasks/tools/install-kubectl-windows/ + + + + 윈도우에서 kubectl.exe 패스를 추가한다. + 환경 변수 창을 띄운다. + ```bash + Windows 설정 - 시스템 - 정보 - 시스템 정보 - 고급 시스템 설정 - 환경 변수 + ``` + 시스템 변수에 path를 선택하고 추가한다. + +
+ +- Mac +```bash +brew install kubectl +kubectl version --client +``` + + + +
+ +Kubernetes는 kubeconfig라는 YAML 파일을 사용하여 kubectl에 대한 클러스터 인증 정보를 저장합니다. kubeconfig에는 명령을 실행할 때 kubectl이 참조하는 컨텍스트 목록이 포함되어 있습니다. 기본적으로 파일은 $HOME/.kube/config에 저장됩니다. + +클러스터를 만들면 항목이 환경의 kubeconfig에 자동으로 추가되고 현재 컨텍스트가 해당 클러스터로 변경됩니다. + +현재 테스트 과정중에 config 이름이 본인이 설정한 이름으로 구성이 되어 있으니 기존 이름을 config로 변경 합니다. + +- config 화일이 여러개인 경우 아래와 같이 병합 하면 됩니다. + ```bash + export KUBECONFIG=~/.kube/config:~/.kube/config-jakelee + ``` + config가 병합되어 있는지 확인합니다. + + ```bash + kubectl config view + ``` + + +
+ +원하는 k8s를 선택하기 위해 전체 context를 조회 해보고 현재 context를 확인합니다. + +```bash +kubectl config get-contexts +kubectl config current-context +``` + +작업하기 원하는 context ( k8s cluster ) 로 변경 합니다. +설정을 하면 기본 context로 설정이 됩니다. + +```bash +kubectl config use-context my-cluster-name +``` + + + +Cluster 정보를 확인 합니다. + +```bash +kubectl cluster-info +``` + + + +
+ +## Kubectl 활용 + +
+ +### kubectl 명령어 + +
+ +자주 사용하는 kubectl 명령어를 알아봅니다. + + +```bash +# 화일 이름의 리소스를 적용한다. 없으면 insert 있으면 update +# 아래 create/update 명령어를 대체 할 수 있다. +kubectl apply -f [화일이름] +# 화일 이름의 리소스를 생성한다. +kubectl create -f [화일이름] +# 화일 이름의 리소스를 update 한다. +kubectl update -f [화일이름] +# 화일 이름의 리소스를 delete 한다. +kubectl delete -f [화일이름] + +# 해당 리소스 정보를 보여준다 +kubectl get [리소스 타입] [리소스 이름] + +# 해당 리소스 세부 정보를 보여준다 +kubectl describe [리소스 타입] [리소스 이름] + +# 해당 리소스 로그 정보를 보여준다 +kubectl log [리소스 이름] +# 해당 리소스를 삭제 한다 +kubectl delete [리소스 타입] [리소스 이름] + +# Pod ( Container ) 안에서 command를 할 수 있다. +kubectl exec -it [PO 이름] /bin/sh +``` + +전체 레이블을 조회한다. +```bash +root@jakelee:~# kubectl get pods --show-labels +NAME READY STATUS RESTARTS AGE LABELS +flask-edu4-app-74788b6479-qgs2j 1/1 Running 0 24m app=flask-edu4-app,pod-template-hash=74788b6479 +flask-edu4-app-74788b6479-l7gkx 1/1 Running 0 24m app=flask-edu4-app,pod-template-hash=74788b6479 +flask-edu4-app-74788b6479-nmcvv 1/1 Running 0 24m app=flask-edu4-app,pod-template-hash=74788b6479 +flask-edu4-app-74788b6479-f2kcp 1/1 Running 0 24m app=flask-edu4-app,pod-template-hash=74788b6479 +flask-edu4-app-74788b6479-rlght 1/1 Running 0 24m app=flask-edu4-app,pod-template-hash=74788b6479 +``` + +
+ +### 명령 vs 선언 + +
+ +명령보다는 선언하여 사용하는 것을 권장. + +- 명령 + + ```bash + kubectl scale --replicas=3 rs/nginx + ``` + +- 선언 + + ```yaml + apiVersion: apps/v1 + kind: ReplicaSet + metadata: + name: frontend + labels: + app: guestbook + tier: frontend + spec: + # modify replicas according to your case + replicas: 3 + selector: + matchLabels: + tier: frontend + template: + metadata: + labels: + tier: frontend + spec: + containers: + - name: php-redis + image: gcr.io/google_samples/gb-frontend:v3 + ``` + + 위의 화일은 에러가 나기 때문에 아래 사이트에서 복사해서 사용한다. + + 참고 : https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/ + + ```bash + kubectl apply -f [화일명] + ``` + + + + + +
+ +
+ +## kubernetes 리소스 + +
+ +### Node + +
+ + + +`Kubernetes Node` 는 최소한 다음과 같이 동작합니다. + +- Kubelet은, 쿠버네티스 마스터와 노드 간 통신을 책임지는 프로세스이며, 하나의 머신 상에서 동작하는 파드와 컨테이너를 관리합니다. +- (도커, rkt)와 같은 컨테이너 런타임은 레지스트리에서 컨테이너 이미지를 가져와 묶여 있는 것을 풀고 애플리케이션을 동작시키는 책임을 맡습니다. + +Node 정보 확인 +```bash +root@jakelee:~# kubectl get node +NAME STATUS ROLES AGE VERSION +jakelee Ready control-plane,master 2d20h v1.22.7+k3s1 +``` + +Node 상세 정보 확인 +```bash +root@jakelee:~# kubectl get node -o wide +NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME +jakelee Ready control-plane,master 2d20h v1.22.7+k3s1 172.27.0.134 Ubuntu 18.04.6 LTS 5.15.0-051500-generic containerd://1.5.9-k3s1 +``` + +Node 성능 사용량 확인 +```bash +root@jakelee:~# kubectl top nodes +NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% +jakelee 151m 1% 7849Mi 49% +``` + +추가 명령어 +```bash +# 해당노드에 pod 를 스케쥴링 하지 않는다. +kubectl cordon + +# 해당노드에 pod 를 스케쥴링 한다. +kubectl uncordon + +# https://arisu1000.tistory.com/27845 +# 노드 관리를 위해서 지정된 노드에 있는 포드들을 다른곳으로 이동시키는 명령입니다. +kubectl drain +``` + +
+ +### Deployment + +
+ + + +`Deployment`는 Kubernetes 가 애플리케이션의 인스턴스를 어떻게 생성하고 업데이트해야 하는지를 지시합니다. +`Deployment`가 만들어지면, Kubernetes Master 가 해당 `Deployment` 에 포함된 애플리케이션 인스턴스가 클러스터의 개별 노드에서 실행되도록 스케줄합니다. + +
+ +아래 명령어와 같이 수행합니다. + +```bash +kubectl create deployment --image=shclub/edu4:v1 flask-edu4-app +``` + +Deployment 가 생성되고 Pod 가 정상적으로 실행중인지 확인합니다. + +```bash +root@jakelee:~# kubectl get all +NAME READY STATUS RESTARTS AGE +pod/flask-edu4-app-74788b6479-t6rvt 1/1 Running 0 48s + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +service/kubernetes ClusterIP 10.43.0.1 443/TCP 2d17h + +NAME READY UP-TO-DATE AVAILABLE AGE +deployment.apps/flask-edu4-app 1/1 1 1 48s + +NAME DESIRED CURRENT READY AGE +replicaset.apps/flask-edu4-app-74788b6479 1 1 1 48s +``` + + +실행중인 Deployment 를 자세히 확인 해보겠습니다. + +```bash +root@jakelee:~# kubectl describe deployment flask-edu4-app +Name: flask-edu4-app +Namespace: default +CreationTimestamp: Mon, 04 Apr 2022 11:01:34 +0900 +Labels: app=flask-edu4-app +Annotations: deployment.kubernetes.io/revision: 1 +Selector: app=flask-edu4-app +Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable +StrategyType: RollingUpdate +MinReadySeconds: 0 +RollingUpdateStrategy: 25% max unavailable, 25% max surge +Pod Template: + Labels: app=flask-edu4-app + Containers: + edu4: + Image: shclub/edu4:v1 + Port: + Host Port: + Environment: + Mounts: + Volumes: +Conditions: + Type Status Reason + ---- ------ ------ + Available True MinimumReplicasAvailable + Progressing True NewReplicaSetAvailable +OldReplicaSets: +NewReplicaSet: flask-edu4-app-74788b6479 (1/1 replicas created) +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal ScalingReplicaSet 2m11s deployment-controller Scaled up replica set flask-edu4-app-74788b6479 to 1 +``` + +
+ +### Pod + +
+ + + +
+ +Deployment 가 생성이 되고 나면 Kubernetes 는 여러분의 애플리케이션 인스턴스에 Pod 를 생성했습니다. + +Pod 는 하나 또는 그 이상의 애플리케이션 컨테이너 (도커 또는 rkt와 같은)들의 그룹을 나타내는 쿠버네티스의 추상적 개념으로 일부는 컨테이너에 대한 자원을 공유합니다. + +
+ +#### Pod 확인 + +
+ +- pod 정보 확인 + + ```bash + root@jakelee:~# kubectl get pod + NAME READY STATUS RESTARTS AGE + flask-edu4-app-74788b6479-t6rvt 1/1 Running 0 6m49s + ``` +- pod 성능 사용량 확인 + + ```bash + root@jakelee:~# kubectl top pod + NAME CPU(cores) MEMORY(bytes) + flask-edu4-app-74788b6479-t6rvt 1m 17Mi + ``` + 컨테이너 이름까지 같이 보기. + + ```bash + root@jakelee:~# kubectl top pod --containers + POD NAME CPU(cores) MEMORY(bytes) + flask-edu4-app-74788b6479-f2kcp edu4 1m 18Mi + ``` + + +- Pod 내 Container 의 log 확인 + + ```bash + root@jakelee:~# kubectl logs flask-edu4-app-74788b6479-t6rvt + * Serving Flask app 'app' (lazy loading) + * Environment: production + WARNING: This is a development server. Do not use it in a production deployment. + Use a production WSGI server instead. + * Debug mode: off + * Running on all addresses (0.0.0.0) + WARNING: This is a development server. Do not use it in a production deployment. + * Running on http://127.0.0.1:5000 + * Running on http://10.42.0.24:5000 (Press CTRL+C to quit) + ``` + - 실시간 로그 확인 + + ```bash + root@jakelee:~# kubectl logs -f flask-edu4-app-74788b6479-t6rvt + ``` + +- Pod 내 Container 에 명령어 수행 + + ```bash + root@jakelee:~# kubectl exec -it flask-edu4-app-74788b6479-t6rvt /bin/sh + ``` + 하나의 pod에 여러 container가 있는 경우. + + ```bash + root@jakelee:~# kubectl top po --containers -n monitoring + POD NAME CPU(cores) MEMORY(bytes) + alertmanager-prometheus-kube-prometheus-alertmanager-0 alertmanager 1m 21Mi + alertmanager-prometheus-kube-prometheus-alertmanager-0 config-reloader 0m 4Mi + prometheus-grafana-75898f6f7b-mm6zx grafana 4m 44Mi + prometheus-grafana-75898f6f7b-mm6zx grafana-sc-dashboard 3m 61Mi + prometheus-grafana-75898f6f7b-mm6zx grafana-sc-datasources 1m 60Mi + prometheus-kube-prometheus-operator-85bcb96fcb-ct7pj kube-prometheus-stack 1m 35Mi + prometheus-kube-state-metrics-77698656df-82g44 kube-state-metrics 1m 15Mi + prometheus-prometheus-kube-prometheus-prometheus-0 config-reloader 0m 7Mi + prometheus-prometheus-kube-prometheus-prometheus-0 prometheus 112m 548Mi + prometheus-prometheus-node-exporter-5t2jt node-exporter 1m 12Mi + ``` + + -c 옵션과 컨테이너 이름을 입력하면 해당 컨테이너로 진입한다. + + ``` + root@jakelee:~# kubectl exec -it prometheus-prometheus-kube-prometheus-prometheus-0 -c prometheus /bin/sh -n monitoring + kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. + /prometheus $ + ``` +- Pod 상세 정보 확인 - 1 + + ```bash + root@jakelee:~# kubectl get pod -o wide + NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES + flask-edu4-app-74788b6479-t6rvt 1/1 Running 0 17m 10.42.0.24 jakelee + ``` + +- Pod 상세 정보 확인 - 2 + + ```bash + root@jakelee:~# kubectl describe pod flask-edu4-app-74788b6479-t6rvt + Name: flask-edu4-app-74788b6479-t6rvt + Namespace: default + Priority: 0 + Node: jakelee/172.27.0.134 + Start Time: Mon, 04 Apr 2022 11:01:34 +0900 + Labels: app=flask-edu4-app + pod-template-hash=74788b6479 + Annotations: + Status: Running + IP: 10.42.0.24 + IPs: + IP: 10.42.0.24 + Controlled By: ReplicaSet/flask-edu4-app-74788b6479 + Containers: + edu4: + Container ID: containerd://f8d6ebf74ec2b52d2b87141e6e6eeed786b1ce6357ce1c84ab9e1bc76327bc69 + Image: shclub/edu4:v1 + Image ID: docker.io/shclub/edu4@sha256:4c89b421e18699420632a98d15659083034e47dc175b5141a5084080b46c9e47 + Port: + Host Port: + State: Running + Started: Mon, 04 Apr 2022 11:01:41 +0900 + Ready: True + Restart Count: 0 + Environment: + Mounts: + /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-jrmkz (ro) + Conditions: + Type Status + Initialized True + Ready True + ContainersReady True + PodScheduled True + Volumes: + kube-api-access-jrmkz: + Type: Projected (a volume that contains injected data from multiple sources) + TokenExpirationSeconds: 3607 + ConfigMapName: kube-root-ca.crt + ConfigMapOptional: + DownwardAPI: true + QoS Class: BestEffort + Node-Selectors: + 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 19m default-scheduler Successfully assigned default/flask-edu4-app-74788b6479-t6rvt to jakelee + Normal Pulling 19m kubelet Pulling image "shclub/edu4:v1" + Normal Pulled 19m kubelet Successfully pulled image "shclub/edu4:v1" in 5.989302707s + Normal Created 19m kubelet Created container edu4 + Normal Started 19m kubelet Started container edu4 + ``` + +- 현재 실행중인 Pod 의 정보를 yaml 형식으로 출력 + + ```bash + root@jakelee:~# kubectl get pod flask-edu4-app-74788b6479-t6rvt -o yaml + ``` + + 아래와 같이 저장 가능하다. + + ```bash + root@jakelee:~# kubectl get pod flask-edu4-app-74788b6479-t6rvt -o yaml > flask-edu4-app.yml + ``` + + +
+ +#### Pod 생성 + +
+ +아래 명령어를 통해 Pod 을 생성 할 수 있습니다. + +```bash +root@jakelee:~# kubectl run pod-test-app --image=nginx +pod/pod-test-app created +root@jakelee:~# kubectl get po +NAME READY STATUS RESTARTS AGE +flask-edu4-app-74788b6479-t6rvt 1/1 Running 0 24m +pod-test-app 1/1 Running 0 11s +``` + +아래와 같이 yaml 을 이용해서 Pod 을 생성 할 수 있습니다. + +```bash +$ cat << EOF | kubectl create -f - +apiVersion: v1 +kind: Pod +metadata: + labels: + run: pod-test-app-2 + name: pod-test-app-2 + namespace: default +spec: + containers: + - image: nginx + name: pod-test-app-2 +EOF +``` + +또는 + +```bash +kubectl create -f pod-test-app-2.yml +``` + +로컬에 화일이 없는 경우 아래와 같이도 가능하다. + +https://github.com/shclub/edu4/blob/master/pod-test-app-2.yml 를 로컬에 다운 받은 후 실행 + +```bash +kubectl create -f pod-test-app-2.yml +``` + +
+ +#### Pod 삭제 + +
+ +아래 명령어를 통해 Pod 를 삭제 할 수 있습니다. + +```bash +root@jakelee:~# kubectl delete pod pod-test-app +pod "pod-test-app" deleted +``` + +
+ +### Service + +
+ + + +
+ +kubernetes Pod 들은 언젠가는 죽게됩니다. 실제 Pod 들은 생명주기를 갖습니다. + +워커 노드가 죽으면, 노드 상에서 동작하는 Pod 들 또한 종료됩니다. + +Kubernetes 에서 service 는 Pod 들에 접근 할 수 있는 정책을 정의하는 추상적 개념입니다. + +- ClusterIP (기본값) + - 클러스터 내에서 내부 IP 에 대해 서비스를 노출합니다. 이 방식은 클러스터 내에서만 서비스가 접근될 수 있도록 합니다. +- NodePort + - NAT가 이용되는 클러스터 내에서 각각 선택된 노드들의 동일한 포트에 서비스를 노출 시켜줍니다. + `:`를 이용하여 클러스터 외부로부터 서비스가 접근할 수 있도록 해줍니다. ClusterIP 의 상위 집합입니다. +- LoadBalancer + - (지원 가능한 경우) 기존 클라우드에서 외부용 로드밸런서를 생성하고 고정된 공인 IP를 할당합니다. + NodePort 의 상위 집합입니다. +- ExternalName + - 이름으로 CNAME 레코드를 반환함으로써 임의의 이름(Spec 에서 externalName 으로 명시)을 이용하여 서비스를 노출시켜줍니다. + 프록시는 사용되지 않습니다. 이 방식은 kube-dns 버전 1.7 이상에서 지원 가능합니다. + - 외부 서비스를 쿠버네티스 내부에서 호출 하고자 할때 사용할 수 있습니다. + +
+ +앱을 외부에 노출하기. + +아래 명령어를 통해 APP 을 외부에 노출 할 수 있습니다. +현재 Hands on 환경은 LoadBalancer or Ingress 가 사용이 불가능하므로 Nodeport 를 이용하여 TEST 해보도록 하겠습니다. + +expose 옵션 과 create 옵션으로 으로 생성 가능 + +deployment가 있는지 확인합니다. +```bash +root@jakelee:~# kubectl get deployment +NAME READY UP-TO-DATE AVAILABLE AGE +flask-edu4-app 1/1 1 1 80m +``` + +서비스가 있는지 확인합니다. +```bash +root@jakelee:~# kubectl get svc +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubernetes ClusterIP 10.43.0.1 443/TCP 2d19h +``` +APP를 노출합니다. 포트는 컨테이너 포트이고 flask 소스에 5000 번으로 설정. +- 참고 : https://github.com/shclub/edu4/blob/master/app.py + +```bash +root@jakelee:~# kubectl expose deployment flask-edu4-app --port 5000 +service/flask-edu4-app exposed +``` +또는 + +Create 옵션으로 생성 방법 +```bash +root@jakelee:~# kubectl create service clusterip flask-edu4-app --tcp=5000 +service/flask-edu4-app exposed +``` + +서비스를 조회해 보면 80번 포트로 접속할 수 있는 서비스가 생성되었습니다. +```bash +root@jakelee:~# kubectl get svc +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubernetes ClusterIP 10.43.0.1 443/TCP 2d19h +flask-edu4-app ClusterIP 10.43.119.5 5000/TCP 3s +``` + +
+ +### 잠시 Route 설정 시작 + +
+ +오픈 쉬프트에서는 ingress 대신 route를 통해서 외부에서 접근 할수 있게 한다. +아래처럼 oc 명령어를 사용하여 expose하면 외부에서 접근 할 수 있는 url 이 생긴다. + +```bash +root@jakelee:~# oc expose svc/flask-edu4-app --name flask-edu +``` + +route 조회해 본다. + +```bash +root@jakelee:~# kubectl get route +``` + +
+ +### 잠시 Route 설정 끝 + +
+ +위와 명령으로 생성하는 경우, 기본적으로 ClusterIP 로 생성이 됩니다. + +아래 명령을 통해 ClusterIP 를 NodePort 로 변경하도록 하겠습니다. + +```bash +root@jakelee:~# kubectl edit service flask-edu4-app +... +spec: + clusterIP: 10.43.119.5 + clusterIPs: + - 10.43.119.5 + internalTrafficPolicy: Cluster + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: flask-edu4-app + sessionAffinity: None + type: ClusterIP <<< + ... + ``` + +위와 같이 ClusterIP 부분은 NodePort 로 변경하고 저장을 합니다. +(저장 및 종료, VI 과 동일함.) + +NodePort 로 변경이 되었는지 확인합니다. + +포트를 명시하지 않으면 아래와 같이 30000 ~ 32767 범위내에서 자동 할당한다. + +```bash +root@jakelee:~# kubectl edit svc flask-edu4-app +service/flask-edu4-app edited +root@jakelee:~# kubectl get svc +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubernetes ClusterIP 10.43.0.1 443/TCP 2d19h +flask-edu4-app NodePort 10.43.119.5 5000:30685/TCP 9m7s +``` + +위와 같이 30685 로 Port 할당된 것을 확인 할 수 있습니다. +(해당 Port 할당은 따로 yaml 에서 지정을 안하면 랜덤 Mapping 입니다.) + +수동할당시에는 포트를 명시한다. (chapter4 참고 ) + +
+ +서비스를 테스트 해봅니다. 아래와 같이 설정. + +```bash +curl :<할당된 노드 포트 > +``` + +```bash +root@jakelee:~# curl 211.34.231.84:30685 + Container EDU | POD Working : flask-edu4-app-74788b6479-t6rvt | v=1 +``` + +컨테이너 IP로도 테스트 할 수 있다. 포트는 컨테이너 포트 사용. +```bash +root@jakelee:~# curl 211.34.231.84:5000 + Container EDU | POD Working : flask-edu4-app-74788b6479-t6rvt | v=1 +``` + +웹브라우저에서도 테스트 할 수 있다. + + + + +
+ +### Scale Out + +
+ +Pod 을 Scale-out 하는 방법을 실습한다. + +- Before + +- After + +
+ +Command 를 이용하여 Scale-out 를 한다. +기존에 1개의 Pod 으로 실행중이던 APP 을 5개의 Pod 으로 Scale-out 하도록 한다. + +현재 deployment 확인 +```bash +root@jakelee:~# kubectl get deployment +NAME READY UP-TO-DATE AVAILABLE AGE +flask-edu4-app 1/1 1 1 123m +``` +Scale-out 를 한다. +```bash +root@jakelee:~# kubectl scale deployment --replicas=5 flask-edu4-app +deployment.apps/flask-edu4-app scaled +``` + +Scale-out 된 deployment를 확인한다. +```bash +root@jakelee:~# kubectl get deployment +NAME READY UP-TO-DATE AVAILABLE AGE +flask-edu4-app 5/5 5 5 123m +``` + +POD가 5개로 늘어난것을 확인할 수 있고 신규로 4개가 생성되었다. +```bash +root@jakelee:~# kubectl get po +NAME READY STATUS RESTARTS AGE +flask-edu4-app-74788b6479-t6rvt 1/1 Running 0 126m +flask-edu4-app-74788b6479-l59sp 1/1 Running 0 2m30s +flask-edu4-app-74788b6479-4krcs 1/1 Running 0 2m30s +flask-edu4-app-74788b6479-gmvtk 1/1 Running 0 2m30s +flask-edu4-app-74788b6479-g9j8x 1/1 Running 0 2m30s +``` + +서비스 확인(Round-Robin)이 되는지 아래 명령어를 사용하여 확인한다. +TEST 환경에 맞게 수정합니다. + +```bash +while true; do curl <본인 VM Public IP>:<할당된 노드포트>; done +``` + +아래와 같이 Scale-out 되어 서비스 중인 것을 볼 수 있습니다. + +```bash +root@jakelee:~# while true; do curl 210.106.105.165:30685; done + Container EDU | POD Working : flask-edu4-app-74788b6479-l59sp | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-gmvtk | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-4krcs | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-gmvtk | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-gmvtk | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-gmvtk | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-l59sp | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-g9j8x | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-4krcs | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-t6rvt | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-gmvtk | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-g9j8x | v=1 +``` + + +
+ +## 배포 ( Rolling Update / Rollback ) + +
+ +### Update APP + +
+ +Rolling Update / Rollback APP 에 대한 방법을 실습한다. + +https://github.com/shclub/edu4 의 저장소의 file을 update 한다. + +- python app.py의 소스를 Update 합니다. + +- Jenkins 의 소스를 Update 합니다. 리포지토리는 edu4로 이미 변경 + +
+ +Jenkins 로 빌드 하여 새로운 버전의 도커이미지를 생성합니다. +v2버전이 생성된것을 확인 할 수 있다. + + + +시간 관계상 Push 된 이미지를 사용할 것입니다. + +Container Image Tag : shclub/edu4:v2 + + +
+ +### Rolling Update + +
+ +아래 명령을 통해 기존에 v1 에서 v2 로 image 를 변경하여 Rolling Update 해보겠습니다. + +- 기존정보 + +```bash +root@jakelee:~# kubectl describe deployments flask-edu4-app +Name: flask-edu4-app +Namespace: default +CreationTimestamp: Mon, 04 Apr 2022 11:01:34 +0900 +Labels: app=flask-edu4-app +Annotations: deployment.kubernetes.io/revision: 1 +Selector: app=flask-edu4-app +Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable +StrategyType: RollingUpdate +MinReadySeconds: 0 +RollingUpdateStrategy: 25% max unavailable, 25% max surge +Pod Template: + Labels: app=flask-edu4-app + Containers: + edu4: + Image: shclub/edu4:v1 + Port: + Host Port: + Environment: + Mounts: + Volumes: +Conditions: + Type Status Reason + ---- ------ ------ + Progressing True NewReplicaSetAvailable + Available True MinimumReplicasAvailable +OldReplicaSets: +NewReplicaSet: flask-edu4-app-74788b6479 (5/5 replicas created) +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal ScalingReplicaSet 23m (x2 over 80m) deployment-controller Scaled up replica set flask-edu4-app-74788b6479 to 5 +``` + +- 이미지를 변경합니다. 켠테이너 이름은 describe 에서 containers 밑에 있는 이름 이고 여기에서는 edu4 이다. + +```bash +kubectl set image deployments <컨테이너이름>=<변경할 이미지> +``` + +```bash +root@jakelee:~# kubectl set image deployments flask-edu4-app edu4=shclub/edu4:v2 +deployment.apps/flask-edu4-app image updated +``` + +- Rolling Update 상태 확인 + - 상태 확인 + ```bash + root@jakelee:~# kubectl rollout status deployments flask-edu4-app + Waiting for deployment "flask-edu4-app" rollout to finish: 1 old replicas are pending termination... + Waiting for deployment "flask-edu4-app" rollout to finish: 1 old replicas are pending termination... + Waiting for deployment "flask-edu4-app" rollout to finish: 1 old replicas are pending termination... + deployment "flask-edu4-app" successfully rolled out + ``` + - 실제 서비스 확인 : v2로 바뀐것을 확인 할 수 있다. + ```bash + root@jakelee:~# while true; do curl 210.106.105.165:30685; done + Container EDU | POD Working : flask-edu4-app-757bcc87db-ft9k9 | v=2 + Container EDU | POD Working : flask-edu4-app-757bcc87db-sns6z | v=2 + Container EDU | POD Working : flask-edu4-app-757bcc87db-l69b8 | v=2 + Container EDU | POD Working : flask-edu4-app-757bcc87db-x9fvn | v=2 + Container EDU | POD Working : flask-edu4-app-757bcc87db-l69b8 | v=2 + Container EDU | POD Working : flask-edu4-app-757bcc87db-ft9k9 | v=2 + Container EDU | POD Working : flask-edu4-app-757bcc87db-sns6z | v=2 + ``` + +- 변경 확인 + +```bash +root@jakelee:~# kubectl describe deployments flask-edu4-app +Name: flask-edu4-app +Namespace: default +CreationTimestamp: Mon, 04 Apr 2022 11:01:34 +0900 +Labels: app=flask-edu4-app +Annotations: deployment.kubernetes.io/revision: 2 +Selector: app=flask-edu4-app +Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable +StrategyType: RollingUpdate +MinReadySeconds: 0 +RollingUpdateStrategy: 25% max unavailable, 25% max surge +Pod Template: + Labels: app=flask-edu4-app + Containers: + edu4: + Image: shclub/edu4:v2 + Port: + Host Port: + Environment: + Mounts: + Volumes: +Conditions: + Type Status Reason + ---- ------ ------ + Available True MinimumReplicasAvailable + Progressing True NewReplicaSetAvailable +OldReplicaSets: +NewReplicaSet: flask-edu4-app-757bcc87db (5/5 replicas created) +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal ScalingReplicaSet 34m (x2 over 91m) deployment-controller Scaled up replica set flask-edu4-app-74788b6479 to 5 + Normal ScalingReplicaSet 7m12s deployment-controller Scaled up replica set flask-edu4-app-757bcc87db to 2 + Normal ScalingReplicaSet 7m12s deployment-controller Scaled down replica set flask-edu4-app-74788b6479 to 4 + Normal ScalingReplicaSet 7m11s deployment-controller Scaled up replica set flask-edu4-app-757bcc87db to 3 + Normal ScalingReplicaSet 7m2s deployment-controller Scaled down replica set flask-edu4-app-74788b6479 to 3 + Normal ScalingReplicaSet 7m2s deployment-controller Scaled up replica set flask-edu4-app-757bcc87db to 4 + Normal ScalingReplicaSet 7m2s (x2 over 78m) deployment-controller Scaled down replica set flask-edu4-app-74788b6479 to 1 + Normal ScalingReplicaSet 7m2s deployment-controller Scaled up replica set flask-edu4-app-757bcc87db to 5 + Normal ScalingReplicaSet 7m1s deployment-controller Scaled down replica set flask-edu4-app-74788b6479 to 0 + ``` + + +
+ +### Rollback + +
+ +Rollback 은 배포된 APP 에 문제가 있을 때, 다시 이전 이미지로 배포 해야 되는 경우 사용하는 방법입니다. +(꼭 문제가 있어야 사용이 가능한 것은 아님, 주 목적은 이전 버전으로 Rollback 하기 위함입니다.) + + +- Rollback 진행 + - 현재 상태 확인 : 2개의 Revision 이 있고 2번이 현재 버전이다. + ```bash + root@jakelee:~# kubectl rollout history deployment flask-edu4-app + deployment.apps/flask-edu4-app + REVISION CHANGE-CAUSE + 1 + 2 + ``` + - Rollback 진행 : 바로 이전 버전으로 진행이 된다. + ```bash + root@jakelee:~# kubectl rollout undo deployment flask-edu4-app + deployment.apps/flask-edu4-app rolled back + ``` + - Rollback 확인 : 이미지는 shclub/edu4:v1 으로 변경이 되면 Revision은 3으로 올라간다. + ```bash + root@jakelee:~# kubectl describe deployments.apps flask-edu4-app + Name: flask-edu4-app + Namespace: default + CreationTimestamp: Mon, 04 Apr 2022 11:01:34 +0900 + Labels: app=flask-edu4-app + Annotations: deployment.kubernetes.io/revision: 3 + Selector: app=flask-edu4-app + Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable + StrategyType: RollingUpdate + MinReadySeconds: 0 + RollingUpdateStrategy: 25% max unavailable, 25% max surge + Pod Template: + Labels: app=flask-edu4-app + Containers: + edu4: + Image: shclub/edu4:v1 + Port: + Host Port: + Environment: + Mounts: + Volumes: + Conditions: + Type Status Reason + ---- ------ ------ + Available True MinimumReplicasAvailable + Progressing True NewReplicaSetAvailable + OldReplicaSets: + NewReplicaSet: flask-edu4-app-74788b6479 (5/5 replicas created) + Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal ScalingReplicaSet 14m deployment-controller Scaled down replica set flask-edu4-app-74788b6479 to 4 + Normal ScalingReplicaSet 14m deployment-controller Scaled up replica set flask-edu4-app-757bcc87db to 2 + Normal ScalingReplicaSet 14m deployment-controller Scaled up replica set flask-edu4-app-757bcc87db to 3 + Normal ScalingReplicaSet 13m deployment-controller Scaled up replica set flask-edu4-app-757bcc87db to 5 + Normal ScalingReplicaSet 13m deployment-controller Scaled down replica set flask-edu4-app-74788b6479 to 3 + Normal ScalingReplicaSet 13m deployment-controller Scaled up replica set flask-edu4-app-757bcc87db to 4 + Normal ScalingReplicaSet 13m (x2 over 85m) deployment-controller Scaled down replica set flask-edu4-app-74788b6479 to 1 + Normal ScalingReplicaSet 13m deployment-controller Scaled down replica set flask-edu4-app-74788b6479 to 0 + Normal ScalingReplicaSet 14s deployment-controller Scaled up replica set flask-edu4-app-74788b6479 to 3 + Normal ScalingReplicaSet 14s deployment-controller Scaled down replica set flask-edu4-app-757bcc87db to 4 + Normal ScalingReplicaSet 14s deployment-controller Scaled up replica set flask-edu4-app-74788b6479 to 2 + Normal ScalingReplicaSet 13s deployment-controller Scaled down replica set flask-edu4-app-757bcc87db to 3 + Normal ScalingReplicaSet 13s deployment-controller Scaled up replica set flask-edu4-app-74788b6479 to 4 + Normal ScalingReplicaSet 13s deployment-controller Scaled down replica set flask-edu4-app-757bcc87db to 2 + Normal ScalingReplicaSet 13s (x3 over 98m) deployment-controller Scaled up replica set flask-edu4-app-74788b6479 to 5 + Normal ScalingReplicaSet 12s deployment-controller Scaled down replica set flask-edu4-app-757bcc87db to 1 + Normal ScalingReplicaSet 10s deployment-controller Scaled down replica set flask-edu4-app-757bcc87db to 0 + ``` + + - Rollback 완료 : v1으로 서비스가 변경이 되었다. + ```bash + root@jakelee:~# while true; do curl 210.106.105.165:30685; done + Container EDU | POD Working : flask-edu4-app-74788b6479-qgs2j | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-qgs2j | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-qgs2j | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-qgs2j | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-f2kcp | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-f2kcp | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-l7gkx | v=1 + Container EDU | POD Working : flask-edu4-app-74788b6479-l7gkx | v=1 + ``` + + - 특정 revision 으로 변경하는 방법 + ```bash + kubectl rollout undo deployment flask-edu4-app --to-revision=1 + ``` + +
+ +## Serivce Expose ( Ingress / Route) + +
+ +### Ingress / Route + +
+ + +Ingress는 도메인으로 서비스를 접속하기위해 필요한 오브젝트입니다. + +하나의 클러스터에서 여러 가지 서비스를 운영한다면 외부 연결을 어떻게 할까요? NodePort를 이용하면 서비스 개수만큼 포트를 오픈하고 사용자에게 어떤 포트인지 알려줘야 합니다. 그럴순 없죠! + + + +
+ +위 샘플은 example.com, subicura.com/blog, subicura.com/help 주소로 서로 다른 서비스에 접근하는 모습입니다. + +80(http) 또는 443(https) 포트로 여러 개의 서비스를 연결해야 하는데 이럴 때 Ingress를 사용합니다. + +- wildcard DNS +ip를 기반으로 도메인을 쉽게 사용할 수 있습니다. 실습에서 사용합니다. + + - sslip.io + - xip.io + - nip.io + + ```bash + 10.0.0.1.nip.io maps to 10.0.0.1 + 192-168-1-250.nip.io maps to 192.168.1.250 + app.10.8.0.1.nip.io maps to 10.8.0.1 + app-37-247-48-68.nip.io maps to 37.247.48.68 + customer1.app.10.0.0.1.nip.io maps to 10.0.0.1 + customer2-app-127-0-0-1.nip.io maps to 127.0.0.1 + ``` + +Ingress Nginx 를 설치한다. + +```bash +root@jakelee:~# kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/baremetal/deploy.yaml +``` + +설치가 완료되면 ingress-nginx namespace가 생기고 서비스는 NodePort로 아래와 같이 자동으로 설정이 되어 있다. + +- http : 31996 , https : 31023 + +```bash +root@jakelee:~# kubectl get all -n ingress-nginx +NAME READY STATUS RESTARTS AGE +pod/ingress-nginx-admission-create--1-w9z7x 0/1 Completed 0 11m +pod/ingress-nginx-admission-patch--1-v9v66 0/1 Completed 1 11m +pod/ingress-nginx-controller-8cf5559f8-nc96z 1/1 Running 0 11m + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +service/ingress-nginx-controller-admission ClusterIP 10.43.52.204 443/TCP 11m +service/ingress-nginx-controller NodePort 10.43.27.14 80:31996/TCP,443:31023/TCP 11m + +NAME READY UP-TO-DATE AVAILABLE AGE +deployment.apps/ingress-nginx-controller 1/1 1 1 11m + +NAME DESIRED CURRENT READY AGE +replicaset.apps/ingress-nginx-controller-8cf5559f8 1 1 1 11m + +NAME COMPLETIONS DURATION AGE +job.batch/ingress-nginx-admission-create 1/1 6s 11m +job.batch/ingress-nginx-admission-patch 1/1 7s 11m +``` + +서비스와 포트를 확인하고 정상 작동하는지 확인한다. +```bash +root@jakelee:~# kubectl get svc -n ingress-nginx +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +ingress-nginx-controller-admission ClusterIP 10.43.52.204 443/TCP 147m +ingress-nginx-controller NodePort 10.43.27.14 80:31996/TCP,443:31023/TCP 147m + +root@jakelee:~# curl -I http://127.0.0.1:31996/healthz +HTTP/1.1 200 OK +Date: Mon, 04 Apr 2022 09:07:43 GMT +Content-Type: text/html +Content-Length: 0 +Connection: keep-alive + +# 본인 VM Public IP 로도 확인 가능하다. +root@jakelee:~# curl -I http://210.106.105.165:31996/healthz +HTTP/1.1 200 OK +Date: Mon, 04 Apr 2022 09:14:52 GMT +Content-Type: text/html +Content-Length: 0 +Connection: keep-alive + +# 본인 VM 도메인 으로도 확인 가능하다. +root@jakelee:~# curl -I http://210.106.105.165.nip.io:31996/healthz +HTTP/1.1 200 OK +Date: Mon, 04 Apr 2022 09:46:17 GMT +Content-Type: text/html +Content-Length: 0 +Connection: keep-alive +``` + +서비스를 도메인으로 접속하기 위해서 ingress를 설정한다. +해당 화일은 https://github.com/shclub/edu4/blob/master/ingress_sample1.yaml 에서 다운 받는다. + +backend.service.port.number는 해당 서비스의 컨테이너 포트를 명시한다. + + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: nginx-ingress + annotations: + kubernetes.io/ingress.class: "nginx" + ingress.kubernetes.io/rewrite-target: / + ingressclass.kubernetes.io/is-default-class: "true" +spec: + rules: + - host: 210.106.105.165.nip.io + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: flask-edu4-app + port: + number: 5000 +``` + +```bash +root@jakelee:~# kubectl apply -f ingress-sample1.yaml +ingress.networking.k8s.io/nginx-ingress created +root@jakelee:~# kubectl get ing +NAME CLASS HOSTS ADDRESS PORTS AGE +nginx-ingress nginx 210.106.105.165.nip.io 172.27.0.134 80 12m +``` + +ingress를 통하여 서비스를 접속하여 봅니다. + +```bash +root@jakelee:~# curl http://210.106.105.165.nip.io:31996/ + Container EDU | POD Working : flask-edu4-app-74788b6479-rlght | v=1 +``` + +웹으로도 서비스를 접속하여 봅니다. + + + +
+ +ingressclass를 ingress 마다 넣어주는 불편은 아래와 같이 변경하면 ingress yaml 생성시 annotation 에서 삭제 가능하다. + +```bash +root@jakelee:~# kubectl get ingressclasses --namespace=ingress-nginx +NAME CONTROLLER PARAMETERS AGE +nginx k8s.io/ingress-nginx 3h35m +root@jakelee:~# kubectl edit ingressclasses nginx --namespace=ingress-nginx +``` + +아래와 같이 ingressclass를 추가한다. + +```bash +metadata: + annotations: + ingressclass.kubernetes.io/is-default-class: "true" <<추가 +``` + +
+ +
+ +### Ingress - Traefik + +
+ + +k3s 에는 default 로 Traefik 이라는 Ingress Controller가 설치가 되어 있다. + +Traefik을 사용하여 80/443 포트로 접속하는 방법에 대해서 실습을 한다. + +traefik pod를 확인한다. + +```bash +root@jakelee:~# kubectl get po -n kube-system +NAME READY STATUS RESTARTS AGE +local-path-provisioner-84bb864455-pkktg 1/1 Running 0 9d +helm-install-traefik-crd--1-2l5b9 0/1 Completed 0 9d +svclb-traefik-xst65 2/2 Running 1 (9d ago) 9d +coredns-96cc4f57d-f87gg 1/1 Running 0 9d +metrics-server-ff9dbcb6c-h9tv2 1/1 Running 0 9d +helm-install-traefik--1-5g9lq 0/1 Completed 0 36m +traefik-747c4ffbd6-q6hpd 1/1 Running 0 36m +``` + +traefik service를 확인한다. + +```bash +root@jakelee:~# kubectl get svc traefik -n kube-system +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +traefik LoadBalancer 10.43.167.187 172.27.0.134 80:30622/TCP,443:31534/TCP 9d +``` + +Ingress를 생성하기 전에 inspekt라는 pod를 inspect하는 서비스를 생성한다. + +```bash +root@jakelee:~# kubectl apply -k github.com/shclub/inspekt +``` + +Pod와 서비스가 생성된 것을 확인한다. + + + +ingress를 생성하기 위해 vi 에디터로 inspekt_ingress.yaml 화일을 생성한다. +- 여기에서도 다운 가능 : https://github.com/shclub/edu4/blob/master/inspekt_ingress.yaml + +아래에 kubernetes.io/ingress.class: traefik 의미는 traefik의 ingress controller를 사용하겠다는 의미이다. + +서비스 포트는 컨테이너 포트이다. + +```bash +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: inspekt-traefik-ingress + annotations: + ingress.kubernetes.io/rewrite-target: "/" + kubernetes.io/ingress.class: traefik +spec: + rules: + - host: inspekt.210.106.105.165.sslip.io + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: inspekt + port: + number: 80 + +``` + +해당 화일을 적용하고 ingress가 신규로 생성된 것을 확인 할 수 있다. + +```bash +root@jakelee:~# kubectl apply -f inspekt_ingress.yaml +ingress.networking.k8s.io/inspekt-traefik-ingress created +root@jakelee:~# kubectl get ing +NAME CLASS HOSTS ADDRESS PORTS AGE +flask-edu4-app-v1 nginx 210.106.105.165.nip.io 172.27.0.134 80 3d12h +inspekt-traefik-ingress inspekt.210.106.105.165.sslip.io 172.27.0.134 80 5s +``` + +hosts 의 값을 복사하여 web browser 에서 실행한다. +80번 포트로 접속이 된것을 확인 할 수 있다. + + + +
+ +http (80) 포트인 경우는 위와 같이 가능하지만 https (443) 인 경우는 서비스 마다 인증서를 만들어 추가 해야한다. + +우리는 교육용이기 때문에 ssl을 적용하지 않고 테스트를 진행한다. + +/var/lib/rancher/k3s/server/manifests/traefik.yaml 화일을 수정한다. + +```bash +root@jakelee:~# vi /var/lib/rancher/k3s/server/manifests/traefik.yaml +``` + +valuesContent 밑에 2개의 라인을 추가한다. ssl verify를 skip 한다는 의미이다. + +```bash +valuesContent: |- + globalArguments: << 추가 + - "--serversTransport.insecureSkipVerify=true" << 추가 +``` + +이제 https(443) 포트 케이스는 ingress로 생성할 준비가 되어 있다. + +ingress를 생성하기 위해 vi 에디터로 argocd_ingress.yaml 화일을 생성한다. +- 여기에서도 다운 가능 : https://github.com/shclub/edu4/blob/master/argocd_ingress.yaml + +argocd는 4주차에 설치 실습이 있어 4주차 설치 이후 아래 내용을 따라 하면 된다. + +argocd 서비스를 확인힌다. + +```bash +root@jakelee:~# kubectl get svc -n argocd +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +argocd-applicationset-controller ClusterIP 10.43.26.65 7000/TCP 9d +argocd-dex-server ClusterIP 10.43.239.221 5556/TCP,5557/TCP,5558/TCP 9d +argocd-metrics ClusterIP 10.43.251.44 8082/TCP 9d +argocd-notifications-controller-metrics ClusterIP 10.43.214.197 9001/TCP 9d +argocd-redis ClusterIP 10.43.12.131 6379/TCP 9d +argocd-repo-server ClusterIP 10.43.132.197 8081/TCP,8084/TCP 9d +argocd-server-metrics ClusterIP 10.43.200.82 8083/TCP 9d +argocd-server NodePort 10.43.247.167 80:30000/TCP,443:30001/TCP 9d +``` + +우리가 ingress 설정을 할 서비스는 argocd-server 이다. + + +```bash +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: argocd-ingress + annotations: + kubernetes.io/ingress.class: traefik + ingress.kubernetes.io/ssl-redirect: "true" + ingress.kubernetes.io/force-ssl-redirect: "true" + ingress.kubernetes.io/ssl-passthrough: "true" +spec: + rules: + - host: argocd.210.106.105.165.sslip.io + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: argocd-server + port: + number: 80 +``` + +argocd namespace에 ingress를 적용하고 ingress를 확인한다. + +```bash +oot@jakelee:~# kubectl apply -f argocd_ingress.yaml -n argocd +ingress.networking.k8s.io/argocd-ingress unchanged +root@jakelee:~# kubectl get ing -n argocd +NAME CLASS HOSTS ADDRESS PORTS AGE +argocd-ingress argocd.210.106.105.165.sslip.io 172.27.0.134 80 65m +``` + +hosts 의 값을 복사하여 web browser 에서 실행한다. +https (443) 로 접속이 된것을 확인 할 수 있다. + + + +
+ +Too many redirect 오류가 발생하거나 로그인이 안되는 경우는 argocd에서 직접 +인증서를 처리하려고 하기 때문에 에러가 발생한다. +deployment에 insecure 옵션을 추가 하면 에러가 발생하지 않는다. + +```bash +root@jakelee:~# kubectl get deploy -n argocd +NAME READY UP-TO-DATE AVAILABLE AGE +argocd-redis 1/1 1 1 9d +argocd-applicationset-controller 1/1 1 1 9d +argocd-notifications-controller 1/1 1 1 9d +argocd-dex-server 1/1 1 1 9d +argocd-repo-server 1/1 1 1 9d +inspekt-deployment 1/1 1 1 13h +argocd-server 1/1 1 1 9d +root@jakelee:~# kubectl edit deploy argocd-server -n argocd +``` + +command 의 argocd-server 밑에 -- insecure를 추가하고 저장하고 나온다. + +argocd-server pod가 자동으로 재 실행 된다. + +```bash + containers: + - command: + - argocd-server + - --insecure << 추가 + env: +``` + +이제 웹에서 다시 로그인을 수행한다. + +
+ +### Horizontal Pod Autoscaler (hpa) + +
+ + +이 실습을 진행하기 위해서는 terminal이 2개 이상 열려 있어야 하며 metric server 가 설치가 되어야 합니다. + +Metric 서버는 api를 통해서 컨테이너 CPU 및 메모리 사용량과 같은 리소스 사용량 메트릭을 제공하는데요, hpa는 이 api를 호출해서 Metric 서버에서 제공해주는 리소스 사용량을 기준으로 scaling 여부를 판단합니다. + +k3s는 metric server가 설치가 이미되어 있습니다. + +설치 방법 +- Metric-server github에서 제공하는 config 파일을 이용해 간단하게 설치할 수 있습니다. 필요하다면 파일을 내려받은 뒤 config 파일을 수정하고 배포하면 됩니다. + ```bash + kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.4.1/components.yaml + ``` + +
+ +예제 참고 : https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/horizontal-pod-autoscaler.html + +
+ +현재 Node의 CPU 사용률을 확인합니다. +```bash +root@jakelee:~# kubectl top nodes +NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% +jakelee 488m 6% 8274Mi 51% +``` +테스트용 php 소스 이미지를 배포합니다. 이 Apache 웹 서버 파드에는 500 millicpu CPU 제한이 지정되며 포트 80에서 제공됩니다. +현재 서버는 CPU : 8core +- requests : 200m ( 초기 설정 ) +- limits : 500m (제한 ) + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: php-apache +spec: + selector: + matchLabels: + run: php-apache + replicas: 1 + template: + metadata: + labels: + run: php-apache + spec: + containers: + - name: php-apache + image: k8s.gcr.io/hpa-example + ports: + - containerPort: 80 + resources: + limits: + cpu: 500m + requests: + cpu: 200m +--- +apiVersion: v1 +kind: Service +metadata: + name: php-apache + labels: + run: php-apache +spec: + ports: + - port: 80 + selector: + run: php-apache +``` + +배포시작. + +```bash +root@jakelee:~# kubectl apply -f https://k8s.io/examples/application/php-apache.yaml +deployment.apps/php-apache created +service/php-apache created +``` + +Deployment와 service가 생성이 되었고 php-apache 배포를 위해 Horizontal Pod Autoscaler 리소스를 생성합니다. + +이 명령을 통해 최소 1개에서 최대 10개의 POD가 배포에 대해 10퍼센트의 CPU 사용률을 달성하려는 자동 조정기가 생성됩니다. +평균 CPU 로드가 10퍼센트 이하인 경우 Autoscaler는 Pod 의 수를 최소 1개로 줄이려고 합니다. +로드가 50퍼센트보다 큰 경우 포드의 수를 최대 10개로 늘이려고 합니다. + +우리는 빠른 테스트를 위해 10% 로 설정하고 테스트를 한다. +터미널 창에서 아래 명령어를 실행한다. + +```bash +root@jakelee:~# kubectl autoscale deployment php-apache --cpu-percent=10 --min=1 --max=10 +horizontalpodautoscaler.autoscaling/php-apache autoscaled +root@jakelee:~# kubectl get hpa php-apache +NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE +php-apache Deployment/php-apache /10% 1 10 0 11s +``` + +실시간으로 hpa 상태를 모니터링 한다. 초기에는 Replica 가 minumum 1 로 설정됩니다. + +```bash +root@jakelee:~# kubectl get hpa php-apache -w +NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE +php-apache Deployment/php-apache 0%/10% 1 10 1 15s +``` + +
+ +새로운 터미널에서 아래와 같이 부하를 줍니다. + +```bash +root@jakelee:~# kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done" +``` + +아래에 ok가 나오면 부하가 들어간다는 의미. + +```bash +If you don't see a command prompt, try pressing enter. +OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK! +``` + +이전 터미널에서 계속 적으로 모니터링 합니다. 부하에 따라 Replica 가 증가하고 최대값인 10으로 증가 된것을 확인 할수 있습니다. + +```bash +root@jakelee:~# kubectl get hpa php-apache -w +NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE +php-apache Deployment/php-apache 0%/10% 1 10 1 15s +php-apache Deployment/php-apache 141%/10% 1 10 1 60s +php-apache Deployment/php-apache 253%/10% 1 10 4 75s +php-apache Deployment/php-apache 236%/10% 1 10 8 90s +``` + +부하를 주는 화면에서 ctrl+c 를 눌러 부하를 중단합니다. +최소값으로 돌아오는데는 5분 이상이 소요가 됩니다. + +```bash +root@jakelee:~# kubectl get hpa php-apache -w +NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE +php-apache Deployment/php-apache 0%/10% 1 10 1 15s +php-apache Deployment/php-apache 141%/10% 1 10 1 60s +php-apache Deployment/php-apache 253%/10% 1 10 4 75s +php-apache Deployment/php-apache 236%/10% 1 10 8 90s +php-apache Deployment/php-apache 97%/10% 1 10 10 105s +php-apache Deployment/php-apache 44%/10% 1 10 10 2m +php-apache Deployment/php-apache 39%/10% 1 10 10 2m15s +php-apache Deployment/php-apache 18%/10% 1 10 10 2m30s +php-apache Deployment/php-apache 2%/10% 1 10 10 2m45s +php-apache Deployment/php-apache 0%/10% 1 10 10 3m +php-apache Deployment/php-apache 0%/10% 1 10 10 7m31s +php-apache Deployment/php-apache 0%/10% 1 10 2 7m46s +php-apache Deployment/php-apache 0%/10% 1 10 1 8m1s +``` + +테스트가 완료 되면 리소스를 삭제합니다. + +```bash +root@jakelee:~# kubectl delete deployment.apps/php-apache service/php-apache horizontalpodautoscaler.autoscaling/php-apache +deployment.apps "php-apache" deleted +service "php-apache" deleted +horizontalpodautoscaler.autoscaling "php-apache" deleted +``` + + + +
+ +### 참고 자료 + +
+ +목록 - blog +
+ +- 커피고래 : https://coffeewhale.com/categories/#kubernetes + +- 60살까지 개발자로 살기 : https://jerryljh.tistory.com/category/%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4%20%EA%B5%90%EC%9C%A1 + +- 민현기 : https://medium.com/dtevangelist +- subicura : https://subicura.com/k8s/ +- wonizz : https://blog.wonizz.tk/ +- wooody92 블로그 : https://wooody92.github.io/categories/# +- 아리수 : https://arisu1000.tistory.com/ +- chhanz : https://chhanz.github.io/ +- devops story : https://cwal.tistory.com/21 +- microk8s : https://sarc.io/index.php/cloud/2197-microk8s +- alice : https://m.blog.naver.com/PostList.naver?blogId=alice_k106 +- d4v1d : https://velog.io/@rhee519 +
+ +목록 - youtube +
+ +- 악분일상 + +- 인프런 초급 : https://youtu.be/qLlo7MAJvT0 +
\ No newline at end of file