├── README.md ├── book-img.png ├── chapters ├── 10 │ ├── README.md │ ├── aws-ebs.yaml │ ├── hostpath-pv.yaml │ ├── my-nfs.yaml │ ├── my-pvc-sc.yaml │ ├── nfs-sc.yaml │ ├── use-nfs-sc.yaml │ ├── use-pvc-sc.yaml │ └── use-pvc.yaml ├── 11 │ ├── README.md │ ├── badsector.yaml │ ├── heavy-cal.yaml │ ├── heavy-load.yaml │ ├── hpa.yaml │ ├── no-tolerate.yaml │ ├── node-affinity.yaml │ ├── pod-affinity.yaml │ ├── pod-antiaffinity.yaml │ ├── redis-cache.yaml │ ├── tolerate.yaml │ └── web-server.yaml ├── 12 │ ├── README.md │ ├── limit-range.yaml │ ├── nginx-pdb.yaml │ ├── pod-exceed.yaml │ └── res-quota.yaml ├── 13 │ ├── README.md │ ├── allow-dmz.yaml │ ├── allow-from-web.yaml │ ├── block-metadata.yaml │ ├── db-accessable.yaml │ ├── deny-all.yaml │ ├── dont-leave-dev.yaml │ ├── nginx-sa.yaml │ ├── read-pods.yaml │ ├── role.yaml │ └── web-open.yaml ├── 14 │ └── README.md ├── 15 │ ├── Dockerfile │ ├── Jenkinsfile │ ├── README.md │ ├── app.py │ ├── argocd-ingress.yaml │ └── pod.yaml ├── 16 │ ├── README.md │ ├── jenkins.yaml │ ├── minio-instance.yaml │ ├── myHelmRelease.yaml │ └── mypod-crd.yaml ├── 17 │ ├── README.md │ ├── dag-diamond.yaml │ ├── error-handlers.yaml │ ├── parallel-steps.yaml │ ├── param.yaml │ ├── serial-step.yaml │ └── single-job.yaml ├── 01 │ ├── Dockerfile │ ├── README.md │ └── hello.py ├── 02 │ └── README.md ├── 03 │ └── README.md ├── 04 │ ├── README.md │ └── mynginx.yaml ├── 05 │ ├── README.md │ ├── cmd.yaml │ ├── downward-env.yaml │ ├── downward-volume.yaml │ ├── env.yaml │ ├── game-volume.yaml │ ├── game.properties │ ├── init-container.yaml │ ├── limits.yaml │ ├── liveness.yaml │ ├── monster-config.yaml │ ├── monster-env.yaml │ ├── mynginx.yaml │ ├── node-selector.yaml │ ├── readiness-cmd.yaml │ ├── readiness.yaml │ ├── requests.yaml │ ├── resources.yaml │ ├── second.yaml │ ├── secret-env.yaml │ ├── secret-envfrom.yaml │ ├── secret-volume.yaml │ ├── special-env.yaml │ ├── user-info-stringdata.yaml │ ├── user-info.properties │ ├── user-info.yaml │ ├── volume-empty.yaml │ └── volume.yaml ├── 06 │ ├── README.md │ ├── cluster-ip.yaml │ ├── external.yaml │ ├── load-bal.yaml │ ├── myservice.yaml │ └── node-port.yaml ├── 07 │ ├── Dockerfile │ ├── README.md │ ├── cronjob.yaml │ ├── fluentd.yaml │ ├── job-bug.yaml │ ├── job.yaml │ ├── mydeploy.yaml │ ├── myreplicaset.yaml │ ├── mysts.yaml │ └── train.py ├── 08 │ └── README.md └── 09 │ ├── README.md │ ├── apache-auth.yaml │ ├── apache-tls-issuer.yaml │ ├── apache-tls.yaml │ ├── domain-based-ingress.yaml │ ├── http-issuer.yaml │ ├── mynginx-ingress.yaml │ └── path-based-ingress.yaml ├── gitops ├── README.md ├── deployment.yaml └── service.yaml └── pipeline-sample ├── Dockerfile ├── README.md ├── app.py ├── test.py └── test.sh /README.md: -------------------------------------------------------------------------------- 1 | 6 | # 핵심만 콕! 쿠버네티스 7 | 8 | - 부제: 쿠버네티스의 핵심을 실습하고 이해하는 9 | - 저자: 유홍근 ([커피고래](https://coffeewhale.com)) 10 | - 출간: 2020년 9월 18일 11 | - 정가: 32,000원 12 | - 페이지: 504 13 | 14 | ## 구매 링크 15 | 16 | - [yes24](http://www.yes24.com/Product/Goods/92426926?OzSrank=2) 17 | - [교보문고](http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9791165920180&orderClick=LAG&Kc=) 18 | - [알라딘](https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=250937523) 19 | - [인터파크](http://book.interpark.com/product/BookDisplay.do?_method=detail&sc.shopNo=0000400000&sc.prdNo=338936080&sc.saNo=003002001&bid1=search&bid2=product&bid3=title&bid4=001) 20 | 21 | ![쿠버네티스_입체이미지](book-img.png) 22 | 23 | ## 책 소개 24 | 25 | > 쿠버네티스 첫 시작을 위한 최고의 선택 26 | 27 | 쿠버네티스를 처음 접하시는 분을 위해 준비하였습니다. 컨테이너, 쿠버네티스 기술에 대해 잘 모르더라도 이 책의 예제를 따라하다보면 어느새 쿠버네티스의 매력에 푹 빠질 것입니다. 쿠버네티스 입문서로 시작하기에 최고의 선택, 여러분도 쿠버네티스라는 거인의 어깨 위에 올라서서 클라우드 네이티브가 꿈꾸는 세상을 바라보시기 바랍니다. 28 | 29 | ## 이 책의 특징 30 | 31 | - 핵심을 위주로 설명하여 쿠버네티스의 큰 그림을 빠르게 이해할 수 있습니다. 32 | - 컨테이너 기술에 대한 기본적인 이해와 장점을 파악할 수 있습니다. 33 | - 예제를 직접 따라 하면서 사용법을 익힐 수 있습니다. 34 | 35 | ## 이 책이 필요한 독자 36 | 37 | - 쿠버네티스를 처음 접해보시는 분 38 | - 클라우드 네이티브 기술에 관심이 많으신 분 39 | - 효율적인 운영 환경을 고민하시는 분 40 | 41 | ## 출판사 리뷰 42 | 43 | 이 책에서는 방대한 시스템인 쿠버네티스를 처음 접할 때 어떤 부분을 집중적으로 살펴볼지 설명하고 최적의 학습 경로를 따라가면서, 단기간에 쿠버네티스에 대해서 이해하고 현실적으로 활용해 볼 수 있는 방법을 제공합니다. 이 책은 쿠버네티스의 모든 내용을 상세히 다루는 레퍼런스 북 형태라기보다는, 전반적인 내용에 대해서 핵심 부분만을 설명하고 직접 실습해 보면서 쿠버네티스의 큰 그림을 이해하는 것에 초점을 맞췄습니다. 각 챕터마다 마무리할 수 있도록 도와주며 참고와 주의를 통해 꿀팁을 확인해볼 수 있습니다. 제목처럼 핵심만 콕! 학습하여 이해해보시기 바랍니다. 44 | 45 | ## 목차 및 예제코드 46 | 47 | 1. [도커 기초](chapters/01) 48 | - 1.1 도커 소개 49 | - 1.2 도커 기본 명령 50 | - 1.3 도커 저장소 51 | - 1.4 도커 파일 작성 52 | - 1.5 도커 실행 고급 53 | - 1.6 마치며 54 | 2. [쿠버네티스 소개](chapters/02) 55 | - 2.1 쿠버네티스란? 56 | - 2.2 쿠버네티스의 기본 개념 57 | - 2.3 아키텍처 58 | - 2.4 장점 59 | - 2.5 마치며 60 | 3. [쿠버네티스 설치](chapters/03) 61 | - 3.1 k3s 소개 62 | - 3.2 k3s 설치하기 63 | - 3.3 마치며 64 | 4. [쿠버네티스 첫 만남](chapters/04) 65 | - 4.1 기본 명령 66 | - 4.2 고급 명령 67 | - 4.3 마치며 68 | 5. [Pod 살펴보기](chapters/05) 69 | - 5.1 Pod 소개 70 | - 5.2 라벨링 시스템 71 | - 5.3 실행 명령 및 파라미터 지정 72 | - 5.4 환경변수 설정 73 | - 5.5 볼륨 연결 74 | - 5.6 리소스 관리 75 | - 5.7 상태 확인 76 | - 5.8 2개 컨테이너 실행 77 | - 5.9 초기화 컨테이너 78 | - 5.10 Config 설정 79 | - 5.11 민감 데이터 관리 80 | - 5.12 메타데이터 전달 81 | - 5.13 마치며 82 | 6. [쿠버네티스 네트워킹](chapters/06) 83 | - 6.1 Service 소개 84 | - 6.2 Service 종류 85 | - 6.3 네트워크 모델 86 | - 6.4 마치며 87 | 7. [쿠버네티스 컨트롤러](chapters/07) 88 | - 7.1 컨트롤러란? 89 | - 7.2 ReplicaSet 90 | - 7.3 Deployment 91 | - 7.4 StatefulSet 92 | - 7.5 DaemonSet 93 | - 7.6 Job & CronJob 94 | - 7.7 마치며 95 | 8. [helm 패키지 매니저](chapters/08) 96 | - 8.1 helm이란? 97 | - 8.2 원격 리파지토리(repository) 98 | - 8.3 외부 chart 설치(WordPress) 99 | - 8.4 마치며 100 | 9. [Ingress 리소스](chapters/09) 101 | - 9.1 Ingress란? 102 | - 9.2 Ingress 기본 사용법 103 | - 9.3 Basic Auth 설정 104 | - 9.4 TLS 설정 105 | - 9.5 마치며 106 | 10. [스토리지](chapters/10) 107 | - 10.1 PersistentVolume 108 | - 10.2 PersistentVolumeClaim 109 | - 10.3 StorageClass 110 | - 10.4 쿠버네티스 스토리지 활용 111 | - 10.5 마치며 112 | 11. [고급 스케줄링](chapters/11) 113 | - 11.1 고가용성 확보 – Pod 레벨 114 | - 11.2 고사용성 확보 – Node 레벨 115 | - 11.3 Taint & Toleration 116 | - 11.4 Affinity & AntiAffinity 117 | - 11.5 마치며 118 | 12. [클러스터 관리](chapters/12) 119 | - 12.1 리소스 관리 120 | - 12.2 노드 관리 121 | - 12.3 Pod 개수 유지 122 | - 12.4 마치며 123 | 13. [접근 제어](chapters/13) 124 | - 13.1 사용자 인증(Authentication) 125 | - 13.2 역할 기반 접근 제어(RBAC) 126 | - 13.2.1 Role (ClusterRole) 127 | - 13.3 네트워크 접근 제어(Network Policy) 128 | - 13.4 마치며 129 | 14. [로깅과 모니터링](chapters/14) 130 | - 14.1 로깅 시스템 구축 131 | - 14.2 리소스 모니터링 시스템 구축 132 | - 14.3 마치며 133 | 15. [CI/CD](chapters/15) 134 | - 15.1 DevOps와 CI/CD 135 | - 15.2 CI 파이프라인 136 | - 15.3 GitOps를 이용한 CD 137 | - 15.4 로컬 쿠버네티스 개발 138 | - 15.5 마치며 139 | 16. [사용자 정의 리소스](chapters/16) 140 | - 16.1 사용자 정의 리소스란? 141 | - 16.2 Operator 패턴 142 | - 16.3 유용한 Operators 143 | - 16.4 마치며 144 | 17. [Workflow 관리](chapters/17) 145 | - 17.1 Argo workflow 소개 146 | - 17.2 Workflow 구성하기 147 | - 17.3 활용 방법 소개 148 | - 17.4 마치며 149 | - 부록 쿠버네티스의 미래 150 | - 클라우드 플랫폼 표준 151 | - 애플리케이션 배포 표준화 152 | - 범용 클러스터 플랫폼 153 | - 마치며 154 | 155 | ## 참고자료 156 | 157 | ### VirtualBox를 이용한 k3s 클러스터 구축 방법 소개 158 | 159 | Chapter 3 `쿠버네티스 설치`에 대한 참고자료입니다. 내 로컬 PC(윈도우)에서 클러스터를 구축하기 위해 VirtualBox를 이용하여 k3s 클러스터를 구축하는 방법에 대해서 소개합니다. 160 | 161 | - [VirtualBox를 이용한 k3s 클러스터 구축](https://coffeewhale.com/kubernetes/cluster/virtualbox/2020/08/31/k8s-virtualbox) 162 | 163 | ### 클라우드 서비스별 클러스터 구축 방법 소개 164 | 165 | Chapter 11 `고급 스케줄링`에서 Node 레벨 고가용성 확보를 위한 Cluster Auto Scaler 예제를 따라하기 위한 클라우드 서비스별 클러스터 구축 방법을 설명드립니다. 166 | 167 | - [AWS EKS 클러스터 구축](https://coffeewhale.com/kubernetes/cluster/eks/2020/09/03/k8s-eks/) 168 | - [GCP GKE 클러스터 구축](https://coffeewhale.com/kubernetes/cluster/gke/2020/09/04/k8s-gke/) 169 | 170 | ### CI Pipeline 샘플코드 171 | 172 | Chapter 15 `CI/CD`에서 Jenkins CI pipeline으로 활용하는 샘플코드입니다. 173 | 174 | - [pipeline-sample/](pipeline-sample/) 디렉토리 참조 바랍니다. 175 | 176 | 177 | ### GitOps 단일 진실의 원천 배포 디렉토리 178 | 179 | Chapter 15 `CI/CD`에서 FluxCD, ArgoCD에서 단일 진실의 원천으로 사용하는 샘플코드입니다. 180 | 181 | - [gitops/](gitops/) 디렉토리 참조 바랍니다. 182 | 183 | ## 오탈자 제보 및 문의 사항 184 | 185 | 다음 2가지 방법을 이용하여 연락주시기 바랍니다. 186 | 187 | - 깃허브 리파지토리 [issue 생성](https://github.com/bjpublic/core_kubernetes/issues/new) 188 | - `hongkunyoo (at) gmail.com` (저자, 유홍근)으로 메일 전송 189 | -------------------------------------------------------------------------------- /book-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjpublic/core_kubernetes/8dc324a861013bbe9f2cfd95419900487216a857/book-img.png -------------------------------------------------------------------------------- /chapters/01/Dockerfile: -------------------------------------------------------------------------------- 1 | # Dockerfile 2 | FROM ubuntu:20.04 3 | 4 | RUN apt-get update \ 5 | && apt-get install -y \ 6 | curl \ 7 | python-dev 8 | 9 | WORKDIR /root 10 | COPY hello.py . 11 | ENV my_ver 1.0 12 | 13 | CMD ["python", "hello.py", "guest"] -------------------------------------------------------------------------------- /chapters/01/README.md: -------------------------------------------------------------------------------- 1 | # 1. 도커기초 2 | 3 | ## 1.1 도커 소개 4 | 5 | ### 1.1.3 도커 설치 6 | 7 | ```bash 8 | sudo apt update && sudo apt install -y docker.io net-tools 9 | sudo usermod -aG docker $USER 10 | 11 | # 서버를 재시작합니다. 12 | sudo reboot 13 | ``` 14 | 15 | 16 | ## 1.2 도커 기본 명령 17 | 18 | ### 1.2.1 컨테이너 실행 19 | 20 | ```bash 21 | sudo apt install -y cowsay 22 | cowsay hello world! 23 | # ______________ 24 | # < hello world! > 25 | # -------------- 26 | # \ ^__^ 27 | # \ (oo)\_______ 28 | # (__)\ )\/\ 29 | # ||----w | 30 | # || || 31 | # 32 | ``` 33 | 34 | ```bash 35 | docker run docker/whalesay cowsay 'hello world!' 36 | # Unable to find image 'docker/whalesay:latest' locally 37 | # latest: Pulling from docker/whalesay 38 | # 23cwc732thk4: Pull complete 39 | # t4nb4f93jc42: Pull complete 40 | # ... 41 | # ______________ 42 | # < hello world! > 43 | # -------------- 44 | # \ 45 | # \ 46 | # \ 47 | # ## . 48 | # ## ## ## == 49 | # ## ## ## ## === 50 | # /""""""""""""""""___/ === 51 | # ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~ 52 | # \______ o __/ 53 | # \ \ __/ 54 | # \____\______/ 55 | ``` 56 | 57 | ```bash 58 | docker run docker/whalesay echo hello 59 | # hello 60 | ``` 61 | 62 | ```bash 63 | # `-d` 옵션 추가 64 | docker run -d nginx 65 | # Unable to find image 'nginx:latest' locally 66 | # latest: Pulling from library/nginx 67 | # 5e6ec7f28fb7: Pull complete 68 | # ab804f9bbcbe: Pull complete 69 | # ... 70 | # d7455a395f1a4745974b0be1372ea58c1499f52f97d96b48f92eb8fa765bc69f 71 | ``` 72 | 73 | 74 | ### 1.2.2 컨테이너 조회 75 | 76 | ```bash 77 | docker ps 78 | ``` 79 | 80 | ### 1.2.3 컨테이너 상세 정보 확인 81 | 82 | ```bash 83 | # docker ps를 통해 얻은 로 상세 정보 확인 84 | docker inspect d7455a395f1a 85 | # [ 86 | # { 87 | # "Id": "d7455a395f1a0f562af7a0878397953331b791c229a31b7eba0", 88 | # "Created": "2020-07-12T05:26:23.554118194Z", 89 | # "Path": "/", 90 | # "Args": [ 91 | # ], 92 | # "State": { 93 | # "Status": "running", 94 | # "Running": true, 95 | # "Paused": false, 96 | # ... 97 | ``` 98 | 99 | ### 1.2.4 컨테이너 로깅 100 | 101 | ```bash 102 | docker logs -f d7455a395f1a 103 | # /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, ... 104 | # /docker-entrypoint.sh: Looking for shell scripts in ... 105 | # ... 106 | ``` 107 | 108 | `+`로 로깅을 종료 109 | 110 | ### 1.2.5 컨테이너 명령전달 111 | 112 | ```bash 113 | # 새로운 패키지 설치 114 | docker exec d7455a395f1a sh -c 'apt update && apt install -y wget' 115 | docker exec d7455a395f1a wget localhost 116 | # .. 117 | # Saving to: 'index.html' 118 | # 0K .......... .. 166M=0s 119 | # 2020-07-16 15:15:43 (166 MB/s) - 'index.html' saved [13134] 120 | ``` 121 | 122 | ### 1.2.6 컨테이너 / 호스트간 파일 복사 123 | 124 | ```bash 125 | # 호스트에서 컨테이너로 파일 복사 126 | docker cp /etc/passwd d7455a395f1a:/usr/share/nginx/html/. 127 | 128 | # 확인 129 | docker exec d7455a395f1a curl -s localhost/passwd 130 | # root:x:0:0:root:/root:/bin/bash 131 | # daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 132 | # bin:x:2:2:bin:/bin:/usr/sbin/nologin 133 | # ... 134 | 135 | # 반대로 컨테이너에서 호스트로 파일 복사 136 | docker cp d7455a395f1a:/usr/share/nginx/html/index.html . 137 | 138 | # 확인 139 | cat index.html 140 | # 141 | # 142 | # 143 | # Welcome to nginx! 144 | # ... 145 | ``` 146 | 147 | ### 1.2.7 컨테이너 중단 148 | 149 | ```bash 150 | docker stop d7455a395f1a 151 | # d7455a395f1a 152 | 153 | docker ps 154 | # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 155 | 156 | docker ps -a 157 | # CONTAINER ID IMAGE COMMAND ... STATUS PORTS NAMES 158 | # d7455a395f1a nginx "/docker..." ... Exited (0) ... 159 | # ... 160 | ``` 161 | 162 | ### 1.2.8 컨테이너 재개 163 | 164 | ```bash 165 | docker start d7455a395f1a 166 | # d7455a395f1a 167 | 168 | docker ps 169 | # CONTAINER ID IMAGE COMMAND CREATED ... 170 | # d7455a395f1a nginx "/docker-entrypoint.." 4 minutes ago ... 171 | ``` 172 | 173 | ### 1.2.9 컨테이너 삭제 174 | 175 | ```bash 176 | # 컨테이너 중단 177 | docker stop d7455a395f1a 178 | # d7455a395f1a 179 | 180 | # 컨테이너 삭제 181 | docker rm d7455a395f1a 182 | # d7455a395f1a 183 | 184 | # 컨테이너 조회, nginx가 사라졌습니다. 185 | docker ps -a 186 | # CONTAINER ID IMAGE COMMAND ... STATUS ... 187 | # fc47859c2fdc docker/whalesay "echo hello" ... Exited (0) ... 188 | # 32047a546124 docker/whalesay "cowsay ..." ... Exited (0) ... 189 | ``` 190 | 191 | ### 1.2.10 Interactive 컨테이너 192 | 193 | ```bash 194 | docker run -it ubuntu:16.04 bash 195 | # Unable to find image 'ubuntu:16.04' locally 196 | 197 | # 컨테이너 내부 198 | $root@1c23d59f4289:/# 199 | 200 | $root@1c23d59f4289:/# cat /etc/os-release 201 | # NAME="Ubuntu" 202 | # VERSION="16.04.6 LTS (Xenial Xerus)" 203 | # ID=ubuntu 204 | # ID_LIKE=debian 205 | 206 | # 컨테이너에서 빠져 나오기 207 | $root@1c23d59f4289:/# exit 208 | ``` 209 | 210 | ```bash 211 | # 컨테이너 실행 212 | docker run -d nginx 213 | # c4484sc501e9a 214 | 215 | # exec 명령을 통해서 bash 접속 216 | docker exec -it c4484c501e9a bash 217 | 218 | # 컨테이너 내부 219 | $root@c4484c501e9a:/# 220 | ``` 221 | 222 | 223 | ## 1.3 도커 저장소 224 | 225 | ### 1.3.2 이미지 tag 달기 226 | 227 | ```bash 228 | docker tag nginx:latest /nginx:1 229 | ``` 230 | 231 | 232 | ### 1.3.3 이미지 확인 233 | 234 | ```bash 235 | docker images 236 | # REPOSITORY TAG IMAGE ID CREATED SIZE 237 | # nginx latest 89b0e8f41524 2 minutes ago 150MB 238 | # hongkunyoo/nginx latest 89b0e8f41524 2 minutes ago 150MB 239 | # hongkunyoo/nginx 1 89b0e8f41524 2 minutes ago 150MB 240 | # ubuntu 16.04 330ae480cb85 8 days ago 125MB 241 | # docker/whalesay latest 6b362a9f73eb 5 years ago 247MB 242 | ``` 243 | 244 | ### 1.3.4 도커허브 로그인 245 | 246 | ```bash 247 | docker login 248 | # Username: 249 | # Password: **** 250 | # WARNING! Your password will be stored unencrypted in ... 251 | # Configure a credential helper to remove this warning. See 252 | # https://docs.docker.com/engine/reference/commandline/login/#credentials-store 253 | 254 | # Login Succeeded 255 | ``` 256 | 257 | ### 1.3.5 이미지 업로드 258 | 259 | ```bash 260 | docker push /nginx 261 | # The push refers to repository [docker.io/hongkunyoo/nginx] 262 | # f978b9ed3f26: Preparing 263 | # 9040af41bb66: Preparing 264 | ``` 265 | 266 | ### 1.3.6 이미지 다운로드 267 | 268 | ```bash 269 | docker pull redis 270 | # Using default tag: latest 271 | # latest: Pulling from library/redis 272 | # ... 273 | # 85a6a5c53ff0: Pull complete 274 | 275 | docker images 276 | # REPOSITORY TAG IMAGE ID CREATED SIZE 277 | # hongkunyoo/nginx latest 89b0e8f41524 2 minutes ago 150MB 278 | # hongkunyoo/nginx 1 89b0e8f41524 2 minutes ago 150MB 279 | # nginx latest 89b0e8f41524 2 minutes ago 150MB 280 | # redis latest 235592615444 3 weeks ago 104MB 281 | # ubuntu 16.04 330ae480cb85 8 days ago 125MB 282 | # docker/whalesay latest 6b362a9f73eb 5 years ago 247MB 283 | ``` 284 | 285 | ### 1.3.7 이미지 삭제 286 | 287 | ```bash 288 | docker rmi redis 289 | # Untagged: redis:latest 290 | # Untagged: redis@sha256:800f2587bf3376cb01e6307afe599ddce9439deafbd... 291 | # Deleted: sha256:2355926154447ec75b25666ff5df14d1ab54f8bb4abf731be2fcb818c7a7f145 292 | 293 | docker images 294 | # REPOSITORY TAG IMAGE ID CREATED SIZE 295 | # nginx latest 89b0e8f41524 2 minutes ago 150MB 296 | # hongkunyoo/nginx latest 89b0e8f41524 2 minutes ago 150MB 297 | # hongkunyoo/nginx 1 89b0e8f41524 2 minutes ago 150MB 298 | # ubuntu 16.04 330ae480cb85 8 days ago 125MB 299 | # docker/whalesay latest 6b362a9f73eb 5 years ago 247MB 300 | ``` 301 | 302 | ## 1.4 도커파일 작성 303 | 304 | ### 1.4.1 Dockerfile 기초 305 | 306 | ```python 307 | # hello.py 308 | import os 309 | import sys 310 | 311 | my_ver = os.environ["my_ver"] 312 | arg = sys.argv[1] 313 | 314 | print("hello %s, my version is %s!" % (arg, my_ver)) 315 | ``` 316 | 317 | ```Dockerfile 318 | # Dockerfile 319 | FROM ubuntu:20.04 320 | 321 | RUN apt-get update \ 322 | && apt-get install -y \ 323 | curl \ 324 | python-dev 325 | 326 | WORKDIR /root 327 | COPY hello.py . 328 | ENV my_ver 1.0 329 | 330 | CMD ["python", "hello.py", "guest"] 331 | ``` 332 | 333 | ### 1.4.2 도커 빌드 334 | 335 | ```bash 336 | # 현재 디렉토리에 위치한 Dockerfile을 이용하여 hello:1 이미지를 생성하라 337 | docker build . -t hello:1 338 | # Sending build context to Docker daemon 21.5kB 339 | # Step 1/6 : FROM ubuntu:20.04 340 | # ---> 8e4ce0a6ce69 341 | # Step 2/6 : RUN apt-get update && apt-get install -y curl 342 | # ---> Running in 2d62d9ed92f 343 | # ... 344 | 345 | docker run hello:1 346 | # hello guest, my version is 1.0! 347 | 348 | # 파라미터를 넘기게 되면 기존 `CMD`는 override 됩니다. 349 | # echo 350 | docker run hello:1 echo "hello world!" 351 | # hello world! 352 | 353 | # cat 354 | docker run hello:1 cat hello.py 355 | # import os 356 | # import sys 357 | # ... 358 | 359 | # pwd 360 | docker run hello:1 pwd 361 | # /root 362 | ``` 363 | 364 | ```bash 365 | docker run -e my_ver=1.5 hello:1 366 | # hello guest, my version is 1.5! 367 | ``` 368 | 369 | ### 1.4.3 Dockerfile 심화 370 | 371 | #### ARG 372 | 373 | ```Dockerfile 374 | # Dockerfile 375 | FROM ubuntu:20.04 376 | 377 | RUN apt-get update \ 378 | && apt-get install -y \ 379 | curl \ 380 | python-dev 381 | 382 | ARG my_ver=1.0 383 | 384 | WORKDIR /root 385 | COPY hello.py . 386 | ENV my_ver $my_ver 387 | 388 | CMD ["python", "hello.py", "guest"] 389 | ``` 390 | 391 | ```bash 392 | docker build . -t hello:2 --build-arg my_ver=2.0 393 | 394 | docker run hello:2 395 | # hello guest, my version is 2.0! 396 | ``` 397 | 398 | ```bash 399 | docker run -e my_ver=2.5 hello:2 400 | # hello guest, my version is 2.5! 401 | ``` 402 | 403 | #### ENTRYPOINT 404 | 405 | ```Dockerfile 406 | # Dockerfile 407 | FROM ubuntu:20.04 408 | 409 | RUN apt-get update \ 410 | && apt-get install -y \ 411 | curl \ 412 | python-dev 413 | 414 | WORKDIR /root 415 | COPY hello.py . 416 | ENV my_ver 1.0 417 | 418 | ENTRYPOINT ["python", "hello.py", "guest"] 419 | ``` 420 | 421 | ```bash 422 | docker build . -t hello:3 423 | 424 | docker run hello:3 425 | # hello guest, my version is 1.0! 426 | 427 | # 실행명령을 전달해도 ENTRYPOINT 그대로 실행됩니다. 428 | docker run hello:3 echo "hello" 429 | # hello guest, my version is 1.0! 430 | ``` 431 | 432 | ```Dockerfile 433 | # Dockerfile 434 | FROM ubuntu:20.04 435 | 436 | RUN apt-get update \ 437 | && apt-get install -y \ 438 | curl \ 439 | python-dev 440 | 441 | WORKDIR /root 442 | COPY hello.py . 443 | ENV my_ver 1.0 444 | 445 | # guest를 삭제합니다. hello.py가 새로운 파라미터를 받을 수 있게 만듭니다. 446 | ENTRYPOINT ["python", "hello.py"] 447 | ``` 448 | 449 | ```bash 450 | docker build . -t hello:4 451 | 452 | # new-guest 파라미터를 전달합니다. 453 | docker run hello:4 new-guest 454 | # hello new-guest, my version is 1.0! 455 | ``` 456 | 457 | ## 1.5 도커 실행 고급 458 | 459 | ### 1.5.1 Network 460 | 461 | ```bash 462 | docker run -p 5000:80 -d nginx 463 | # rlasdf0234klcvmz904390zxhvksdf230zxc 464 | 465 | # 5000번으로 localhost 호출을 합니다. 466 | curl localhost:5000 467 | # 468 | # 469 | # 470 | # Welcome to nginx! 471 | # ... 472 | 473 | # 내부/공인IP로도 확인해 봅니다. 474 | curl <내부 혹은 공인IP>:5000 475 | # 476 | # 477 | # 478 | # Welcome to nginx! 479 | # ... 480 | ``` 481 | 482 | ### 1.5.2 Volume 483 | 484 | ```bash 485 | # 현재 디렉토리를 컨테이너의 nginx 디렉토리와 연결합니다. 486 | docker run -p 6000:80 -v $(pwd):/usr/share/nginx/html/ -d nginx 487 | 488 | # 현재 디렉토리에 hello.txt 파일을 생성합니다. 489 | echo hello! >> $(pwd)/hello.txt 490 | 491 | # nginx 내부에서 해당 파일이 보이는지 확인합니다. 492 | curl localhost:6000/hello.txt 493 | # hello! 494 | ``` 495 | 496 | ### 1.5.3 Entrypoint 497 | 498 | ```Dockerfile 499 | # Dockerfile 500 | FROM ubuntu:18.04 501 | 502 | ENTRYPOINT ["echo"] 503 | ``` 504 | 505 | ```bash 506 | docker build . -t lets-echo 507 | 508 | docker run lets-echo hello 509 | # hello 510 | 511 | # cat의 결과가 출력되는 것을 기대하나 cat '/etc/passwd' 라는 문자열이 출력됨 512 | docker run lets-echo cat /etc/password 513 | # cat /etc/password 514 | 515 | # entrypoint를 cat 명령으로 override 516 | docker run --entrypoint=cat lets-echo /etc/passwd 517 | # root:x:0:0:root:/root:/bin/bash 518 | # daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 519 | # bin:x:2:2:bin:/bin:/usr/sbin/nologin 520 | # ... 521 | ``` 522 | 523 | ### 1.5.4 User 524 | 525 | ```Dockerfile 526 | # Dockerfile 527 | FROM ubuntu:18.04 528 | 529 | # Ubuntu 유저 생성 530 | RUN adduser --disabled-password --gecos "" ubuntu 531 | 532 | # 컨테이너 실행 시 ubuntu 유저로 설정 533 | USER ubuntu 534 | ``` 535 | 536 | ```bash 537 | # my-user 라는 이미지 생성 538 | docker build . -t my-user 539 | 540 | # ubuntu라는 유저로 컨테이너 실행 541 | docker run -it my-user bash 542 | ubuntu@b09ce82d4a77:/$ 543 | 544 | ubuntu@b09ce82d4a77:/$ apt update 545 | # Reading package lists... Done 546 | # E: List directory /var/lib/apt/lists/partial is missing. 547 | # - Acquire (13: Permission denied) 548 | 549 | ubuntu@b09ce82d4a77:/$ exit 550 | 551 | # 강제로 root 유저 사용 552 | docker run --user root -it my-user bash 553 | root@0ac2522215e8:/$ apt update 554 | # Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease 555 | # Get:2 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB] 556 | # ... 557 | 558 | root@0ac2522215e8:/$ exit 559 | ``` 560 | 561 | ### Clean up 562 | 563 | ```bash 564 | docker rm $(docker ps -aq) -f 565 | docker rmi $(docker images -q) -f 566 | ``` 567 | -------------------------------------------------------------------------------- /chapters/01/hello.py: -------------------------------------------------------------------------------- 1 | # hello.py 2 | import os 3 | import sys 4 | 5 | my_ver = os.environ["my_ver"] 6 | arg = sys.argv[1] 7 | 8 | print("hello %s, my version is %s!" % (arg, my_ver)) 9 | -------------------------------------------------------------------------------- /chapters/02/README.md: -------------------------------------------------------------------------------- 1 | # 2. 쿠버네티스 소개 2 | 3 | ## 쿠버네티스란? 4 | 5 | - 쿠버네티스 공식 웹사이트 : [https://kubernetes.io/](https://kubernetes.io/) 6 | - 쿠버네티스 깃허브 : [https://github.com/kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) 7 | 8 | 9 | ## 쿠버네티스 읽을거리 10 | 11 | ### 블로그 12 | 13 | - [쿠버네티스 전신, Borg](https://kubernetes.io/blog/2015/04/borg-predecessor-to-kubernetes) 14 | - [쿠버네티스란 무엇인가?](https://subicura.com/2019/05/19/kubernetes-basic-1.html) 15 | - [쿠버네티스 관련 블로그: coffeewhale.com](https://coffeewhale.com) 16 | 17 | ### 데모 클러스터 18 | - [Play with k8s](https://labs.play-with-k8s.com/) 19 | - [Playground](https://www.katacoda.com/courses/kubernetes/playground) 20 | 21 | ### Examples & Tutorials 22 | - [쿠버네티스 공식 튜토리얼](https://kubernetes.io/docs/tutorials/) 23 | - [쿠버네티스 example](https://kubernetesbyexample.com/) 24 | 25 | ### 책 26 | - [The Kubernetes Book](https://www.amazon.com/Kubernetes-Book-Version-January-2018-ebook/dp/B072TS9ZQZ/ref=sr_1_3?ie=UTF8&qid=1528625195&sr=8-3&keywords=kubernetes&dpID=41SyKBO3UcL&preST=_SX342_QL70_&dpSrc=srch) 27 | - [Designing Distributed System](https://azure.microsoft.com/en-us/resources/designing-distributed-systems/en-us/) 28 | 29 | -------------------------------------------------------------------------------- /chapters/03/README.md: -------------------------------------------------------------------------------- 1 | # 3. 쿠버네티스 설치 2 | 3 | 4 | ### 3.2.2 마스터 노드 설치 5 | 6 | ```bash 7 | sudo apt update 8 | sudo apt install -y docker.io nfs-common dnsutils curl 9 | 10 | # k3s 마스터 설치 11 | curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="\ 12 | --disable traefik \ 13 | --disable metrics-server \ 14 | --node-name master --docker" \ 15 | INSTALL_K3S_VERSION="v1.18.6+k3s1" sh -s - 16 | 17 | # 마스터 통신을 위한 설정 18 | mkdir ~/.kube 19 | sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config 20 | sudo chown -R $(id -u):$(id -g) ~/.kube 21 | echo "export KUBECONFIG=~/.kube/config" >> ~/.bashrc 22 | source ~/.bashrc 23 | 24 | # 설치 확인 25 | kubectl cluster-info 26 | # Kubernetes master is running at https://127.0.0.1:6443 27 | # CoreDNS is running at https://127.0.0.1:6443/api/v1/namespaces... 28 | # 29 | # To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. 30 | 31 | kubectl get node -o wide 32 | # NAME STATUS ROLES AGE VERSION INTERNAL-IP ... 33 | # master Ready master 27m v1.18.6+k3s1 10.0.1.1 ... 34 | ``` 35 | 36 | ```bash 37 | # 마스터 노드 토큰 확인 38 | NODE_TOKEN=$(sudo cat /var/lib/rancher/k3s/server/node-token) 39 | echo $NODE_TOKEN 40 | # K10e6f5a983710a836b9ad21ca4a99fcxx::server:c8ae61726384c19726022879xx 41 | 42 | MASTER_IP=$(kubectl get node master -ojsonpath="{.status.addresses[0].address}") 43 | echo $MASTER_IP 44 | # 10.0.1.1 45 | ``` 46 | 47 | 48 | ### 3.2.3 워커 노드 추가 49 | 50 | ```bash 51 | NODE_TOKEN=<마스터에서 확인한 토큰 입력> 52 | MASTER_IP=<마스터에서 얻은 내부IP 입력> 53 | 54 | sudo apt update 55 | sudo apt install -y docker.io nfs-common curl 56 | 57 | # k3s 워커 노드 설치 58 | curl -sfL https://get.k3s.io | K3S_URL=https://$MASTER_IP:6443 \ 59 | K3S_TOKEN=$NODE_TOKEN \ 60 | INSTALL_K3S_EXEC="--node-name worker --docker" \ 61 | INSTALL_K3S_VERSION="v1.18.6+k3s1" sh -s - 62 | ``` 63 | 64 | 65 | ### 3.2.4 설치문제 해결 방법 66 | 67 | #### 1) 마스터 노드 로그 확인 68 | 69 | ```bash 70 | # 마스터 노드 상태 확인 71 | sudo systemctl status k3s.service 72 | # * k3s.service - Lightweight Kubernetes 73 | # ... 74 | # CGroup: /system.slice/k3s.service 75 | # └─955 /usr/local/bin/k3s server --disable traefik \ 76 | # --disable metrics-server \ 77 | # --node-name master \ 78 | # --docker 79 | # 80 | # Aug 11 17:37:09 ip-10-0-1-1 k3s[955]: I0811 17:37:09.189289 ... 81 | # Aug 11 17:37:14 ip-10-0-1-1 k3s[955]: I0811 17:37:14.190442 ... 82 | # ... 83 | 84 | # journald 로그 확인 85 | sudo journalctl -u k3s.service 86 | # Jul 13 17:51:08 ip-10-0-1-1 k3s[955]: W0713 17:51:08.168244 ... 87 | # Jul 13 17:51:08 ip-10-0-1-1 k3s[955]: I0713 17:51:08.649295 ... 88 | # ... 89 | ``` 90 | 91 | 에러 메세지나 exception 메세지를 확인합니다. 92 | 93 | #### 2) 워커 노드 로그 확인 94 | 95 | ```bash 96 | # 워커 노드 상태 확인 97 | sudo systemctl status k3s-agent.service 98 | # * k3s-agent.service - Lightweight Kubernetes 99 | # ... 100 | # CGroup: /system.slice/k3s-agent.service 101 | # └─955 /usr/local/bin/k3s agent --token K10e6f5a983710 ..\ 102 | # --server 10.0.1.1 \ 103 | # --node-name worker \ 104 | # --docker 105 | # 106 | # Aug 11 17:37:09 ip-10-0-1-2 k3s[955]: I0811 17:37:09.189289 ... 107 | # Aug 11 17:37:14 ip-10-0-1-2 k3s[955]: I0811 17:37:14.190442 ... 108 | # ... 109 | 110 | # journald 로그 확인 111 | sudo journalctl -u k3s-agent.service 112 | # Jul 13 17:51:08 ip-10-0-1-2 k3s[955]: W0713 17:51:08.168244 ... 113 | # Jul 13 17:51:08 ip-10-0-1-2 k3s[955]: I0713 17:51:08.649295 ... 114 | # ... 115 | ``` 116 | 117 | 체크리스트 118 | 119 | - `NODE_TOKEN` 값이 제대로 설정 되었나요? 120 | - `MASTER_IP`가 제대로 설정 되었나요? 121 | - 워커 노드에서 마스터 노드로 IP 연결이 가능한가요? 122 | - 마스터, 워커 노드에 적절한 포트가 열려 있나요? 123 | 124 | 125 | #### 3) 마스터 & 워커 노드 재설치 126 | 127 | 마스터 노드에서 다음 명령을 수행하여 마스터를 제거하시기 바랍니다. 128 | 129 | ```bash 130 | /usr/local/bin/k3s-uninstall.sh 131 | ``` 132 | 133 | 워커 노드에서 다음 명령을 수행하여 워커를 제거하시기 바랍니다. 134 | 135 | ```bash 136 | /usr/local/bin/k3s-agent-uninstall.sh 137 | ``` 138 | 139 | 삭제 완료 후, 처음부터 다시 재설치를 진행합니다. 140 | 141 | 142 | #### 4) 공식문서 참고 143 | 144 | [https://rancher.com/docs/k3s/latest/en/installation](https://rancher.com/docs/k3s/latest/en/installation) -------------------------------------------------------------------------------- /chapters/04/README.md: -------------------------------------------------------------------------------- 1 | # 4. 쿠버네티스 첫 만남 2 | 3 | ## 4.1 기본 명령 4 | 5 | ### 4.1.1 컨테이너 실행 6 | 7 | ```bash 8 | kubectl run mynginx --image nginx 9 | # pod/mynginx created 10 | ``` 11 | 12 | ### 4.1.2 컨테이너 조회 13 | 14 | ```bash 15 | kubectl get pod 16 | # NAME READY STATUS RESTARTS AGE 17 | # mynginx 1/1 Running 0 2s 18 | ``` 19 | 20 | ```bash 21 | kubectl get pod mynginx -o yaml 22 | # apiVersion: v1 23 | # kind: Pod 24 | # metadata: 25 | # creationTimestamp: "2020-06-21T06:54:52Z" 26 | # labels: 27 | # run: mynginx 28 | # managedFields: 29 | # - apiVersion: v1 30 | # ... 31 | # ... 32 | # name: mynginx 33 | # namespace: default 34 | # resourceVersion: "11160054" 35 | # ... 36 | ``` 37 | 38 | ```bash 39 | kubectl get pod -o wide 40 | # NAME READY STATUS RESTARTS AGE IP NODE ... 41 | # mynginx 1/1 Running 0 6s 10.42.0.226 worker ... 42 | ``` 43 | 44 | ### 4.1.3 컨테이너 상세 정보 확인 45 | 46 | ```bash 47 | kubectl describe pod mynginx 48 | # Name: mynginx 49 | # Namespace: default 50 | # Priority: 0 51 | # Node: worker/10.0.1.2 52 | # Start Time: Sun, 21 Jun 2020 06:54:52 +0000 53 | # Labels: run=mynginx 54 | # Annotations: 55 | # Status: Running 56 | # IP: 10.42.0.155 57 | # IPs: 58 | # IP: 10.42.0.155 59 | # .... 60 | ``` 61 | 62 | ### 4.1.4 컨테이너 로깅 63 | 64 | ```bash 65 | kubectl logs -f mynginx 66 | # /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will ... 67 | # /docker-entrypoint.sh: Looking for shell scripts in /docker-... 68 | # ... 69 | ``` 70 | 71 | ### 4.1.5 컨테이너 명령 전달 72 | 73 | ```bash 74 | # mynginx에 apt-update 명령을 전달합니다. 75 | kubectl exec mynginx -- apt-get update 76 | # Get:1 http://security.debian.org/debian-security buster/updates ... 77 | # Get:2 http://deb.debian.org/debian buster InRelease [121 kB] 78 | # Get:3 http://deb.debian.org/debian buster-updates InRelease [51.9 kB] 79 | # ... 80 | ``` 81 | 82 | ```bash 83 | kubectl exec -it mynginx -- bash 84 | 85 | $root@mynginx:/# hostname 86 | # mynginx 87 | 88 | # 컨테이너 exit 89 | $root@mynginx:/# exit 90 | ``` 91 | 92 | ### 4.1.6 컨테이너 / 호스트간 파일 복사 93 | 94 | ```bash 95 | # --> 96 | kubectl cp /etc/passwd mynginx:/tmp/passwd 97 | 98 | # exec 명령으로 복사가 되었는지 확인합니다. 99 | kubectl exec mynginx -- ls /tmp/passwd 100 | # /tmp/passwd 101 | 102 | kubectl exec mynginx -- cat /tmp/passwd 103 | # root:x:0:0:root:/root:/bin/bash 104 | # daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 105 | # bin:x:2:2:bin:/bin:/usr/sbin/nologin 106 | # ... 107 | ``` 108 | 109 | ### 4.1.7 컨테이너 정보 수정 110 | 111 | ```bash 112 | kubectl edit pod mynginx 113 | # apiVersion: v1 114 | # kind: Pod 115 | # metadata: 116 | # creationTimestamp: "..." 117 | # labels: 118 | # hello: world # <-- 라벨 추가 119 | # run: mynginx 120 | # managedFields: 121 | # ... 122 | ``` 123 | 124 | ```bash 125 | # mynginx 상세 정보 조회 126 | kubectl get pod mynginx -oyaml 127 | # apiVersion: v1 128 | # kind: Pod 129 | # metadata: 130 | # creationTimestamp: "..." 131 | # labels: 132 | # hello: world # <-- 추가된 라벨 학인 133 | # run: mynginx 134 | # ... 135 | ``` 136 | 137 | ### 4.1.8 컨테이너 삭제 138 | 139 | ```bash 140 | kubectl delete pod mynginx 141 | # pod mynginx deleted 142 | 143 | kubectl get pod 144 | # No resources found .. 145 | ``` 146 | 147 | ### 4.1.9 선언형 명령 정의서 (YAML) 기반의 컨테이너 생성 148 | 149 | ```yaml 150 | # mynginx.yaml 151 | apiVersion: v1 152 | kind: Pod 153 | metadata: 154 | name: mynginx 155 | spec: 156 | containers: 157 | - name: mynginx 158 | image: nginx 159 | ``` 160 | 161 | ```bash 162 | ls 163 | # mynginx.yaml 164 | 165 | kubectl apply -f mynginx.yaml 166 | # pod/mynginx created 167 | 168 | kubectl get pod 169 | # NAME READY STATUS RESTARTS AGE 170 | # mynginx 1/1 Running 1 6s 171 | 172 | kubectl get pod mynginx -oyaml 173 | # apiVersion: v1 174 | # kind: Pod 175 | # metadata: 176 | # ... 177 | # name: mynginx 178 | # ... 179 | # spec: 180 | # containers: 181 | # - image: nginx 182 | # name: mynginx 183 | # ... 184 | ``` 185 | 186 | ```bash 187 | kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/pods/simple-pod.yaml 188 | # pod/nginx created 189 | 190 | kubectl delete -f https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/pods/simple-pod.yaml 191 | # pod/nginx deleted 192 | ``` 193 | 194 | ```yaml 195 | # mynginx.yaml 196 | apiVersion: v1 197 | kind: Pod 198 | metadata: 199 | labels: 200 | hello: world # <-- 라벨 추가 201 | name: mynginx 202 | spec: 203 | containers: 204 | - name: mynginx 205 | image: nginx:1.17.2 # <-- 기존 latest에서 1.17.2로 변경 206 | ``` 207 | 208 | ```bash 209 | kubectl apply -f mynginx.yaml 210 | # pod/mynginx configured 211 | 212 | kubectl get pod 213 | # NAME READY STATUS RESTARTS AGE 214 | # mynginx 1/1 Running 1 3m48s 215 | 216 | kubectl get pod mynginx -oyaml 217 | # apiVersion: v1 218 | # kind: Pod 219 | # metadata: 220 | # labels: 221 | # hello: world 222 | # ... 223 | # name: mynginx 224 | # ... 225 | # spec: 226 | # containers: 227 | # - image: nginx:1.17.2 228 | # name: mynginx 229 | # ... 230 | ``` 231 | 232 | ```bash 233 | kubectl apply -f mynginx.yaml 234 | # pod/mynginx unchanged 235 | 236 | kubectl get pod 237 | # NAME READY STATUS RESTARTS AGE 238 | # mynginx 1/1 Running 1 3m48s 239 | 240 | kubectl get pod mynginx -oyaml 241 | # apiVersion: v1 242 | # kind: Pod 243 | # metadata: 244 | # labels: 245 | # hello: world 246 | # ... 247 | # name: mynginx 248 | # ... 249 | # spec: 250 | # containers: 251 | # - image: nginx:1.17.2 252 | # name: mynginx 253 | # ... 254 | ``` 255 | 256 | ## 4.2 고급 명령 257 | 258 | ### 4.2.1 리소스별 명령 259 | 260 | ```bash 261 | kubectl get service 262 | # NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 263 | # kubernetes ClusterIP 10.43.0.1 443/TCP 13d 264 | 265 | # describe 명령도 동일하게 작동합니다. 266 | kubectl describe service kubernetes 267 | # Name: kubernetes 268 | # Namespace: default 269 | # Labels: component=apiserver 270 | # provider=kubernetes 271 | # ... 272 | ``` 273 | 274 | ```bash 275 | kubectl get node 276 | # NAME STATUS ROLES AGE VERSION 277 | # master Ready master 13d v1.18.6+k3s1 278 | # worker Ready 13d v1.18.6+k3s1 279 | 280 | kubectl describe node master 281 | # Name: master 282 | # Roles: master 283 | # Labels: beta.kubernetes.io/arch=amd64 284 | # beta.kubernetes.io/instance-type=k3s 285 | # ... 286 | ``` 287 | 288 | ### 4.2.2 네임스페이스 289 | 290 | ```bash 291 | kubectl get namespace 292 | # NAME STATUS AGE 293 | # default Active 12m 294 | # kube-system Active 12m 295 | # kube-public Active 12m 296 | # kube-node-lease Active 12m 297 | 298 | kubectl describe namespace kube-system 299 | # Name: kube-system 300 | # Labels: 301 | # Annotations: 302 | # ... 303 | ``` 304 | 305 | ```bash 306 | kubectl run mynginx-ns --image nginx --namespace kube-system 307 | # pod/mynginx-ns created 308 | 309 | # kube-system 네임스페이스에서 Pod 확인 310 | kubectl get pod mynginx-ns -n kube-system # --namespace를 -n로 축약 가능 311 | # NAME READY STATUS RESTARTS AGE 312 | # mynginx-ns 1/1 Running 0 13s 313 | 314 | kubectl delete pod mynginx-ns -n kube-system 315 | # pod/mynginx-ns deleted 316 | ``` 317 | 318 | ```bash 319 | kubectl get pod -n default 320 | # NAME READY STATUS RESTARTS AGE 321 | # mynginx 1/1 Running 0 71m 322 | 323 | kubectl get pod 324 | # NAME READY STATUS RESTARTS AGE 325 | # mynginx 1/1 Running 0 71m 326 | ``` 327 | 328 | ### 4.2.3 자동완성 기능 329 | 330 | [https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion](https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion) 331 | 332 | ```bash 333 | echo 'source <(kubectl completion bash)' >> ~/.bashrc 334 | source ~/.bashrc 335 | ``` 336 | 337 | ```bash 338 | kubectl run yournginx --image nginx 339 | # pod/yournginx created 340 | ``` 341 | 342 | ```bash 343 | kubectl get pod 344 | # mynginx yournginx 345 | ``` 346 | 347 | ### 4.2.4 즉석 리소스 생성 348 | 349 | ```bash 350 | # 즉석에서 YALM 문서를 생성하여 쿠버네티스에게 전달 351 | cat << EOF | kubectl apply -f - 352 | apiVersion: v1 353 | kind: Pod 354 | metadata: 355 | name: cat-nginx 356 | spec: 357 | containers: 358 | - image: nginx 359 | name: cat-nginx 360 | EOF 361 | # pod/cat-nginx created 362 | ``` 363 | 364 | ### 4.2.5 리소스 특정 정보 추출 365 | 366 | ```bash 367 | kubectl get node master -o yaml 368 | # apiVersion: v1 369 | # kind: Node 370 | # metadata: 371 | # annotations: 372 | # ... 373 | # spec: 374 | # podCIDR: 10.42.0.0/24 375 | # podCIDRs: 376 | # - 10.42.0.0/24 377 | # providerID: k3s://master 378 | # status: 379 | # addresses: 380 | # - address: 10.0.1.1 381 | # type: InternalIP 382 | # - address: master 383 | # type: Hostname 384 | ``` 385 | 386 | ```bash 387 | kubectl get node master -o wide 388 | # NAME STATUS ROLES AGE VERSION INTERNAL-IP ... 389 | # master Ready master 27m v1.18.6+k3s1 10.0.1.1 ... 390 | ``` 391 | 392 | ```bash 393 | kubectl get node master -o jsonpath="{.status.addresses[0].address}" 394 | # 10.0.1.1 395 | ``` 396 | 397 | `jsonpath`에 대한 상세 사용법 참고 398 | 399 | [https://kubernetes.io/docs/reference/kubectl/jsonpath](https://kubernetes.io/docs/reference/kubectl/jsonpath/) 400 | 401 | ### 4.2.6 모든 리소스 조회 402 | 403 | ```bash 404 | kubectl api-resources 405 | # NAME SHORTNAMES APIGROUP NAMESPACED KIND 406 | # namespaces ns false Namespace 407 | # nodes no false Node 408 | # pods po true Pod 409 | # ... 410 | ``` 411 | 412 | ```bash 413 | kubectl api-resources --namespaced=true 414 | # NAME SHORTNAMES APIGROUP NAMESPACED KIND 415 | # bindings true Binding 416 | # configmaps cm true ConfigMap 417 | # endpoints ep true Endpoints 418 | # events ev true Event 419 | ``` 420 | 421 | ### 4.2.7 리소스 설명 422 | 423 | ```bash 424 | # Pod에 대한 정의를 확인할 수 있습니다. 425 | kubectl explain pods 426 | # KIND: Pod 427 | # VERSION: v1 428 | # 429 | # DESCRIPTION: 430 | # Pod is a collection of containers that can run on a host. 431 | # This resource is created by clients and scheduled onto hosts. 432 | # 433 | # FIELDS: 434 | # apiVersion 435 | # APIVersion defines the versioned schema of this representation 436 | # .... 437 | ``` 438 | 439 | ### 4.2.8 클러스터 상태 확인 440 | 441 | ```bash 442 | # 쿠버네티스 API서버 작동 여부 확인 443 | kubectl cluster-info 444 | 445 | # 전체 노드 상태 확인 446 | kubectl get node 447 | 448 | # 쿠버네티스 핵심 컴포넌트의 Pod 상태 확인 449 | kubectl get pod -n kube-system 450 | ``` 451 | 452 | ### 4.2.9 클라이언트 설정파일 453 | 454 | ```bash 455 | kubectl config view 456 | # apiVersion: v1 457 | # clusters: 458 | # - cluster: 459 | # certificate-authority-data: DATA+OMITTED 460 | # server: https://127.0.0.1:6443 461 | # name: default 462 | # ... 463 | ``` 464 | 465 | ```bash 466 | cat $HOME/.kube/config 467 | # apiVersion: v1 468 | # clusters: 469 | # - cluster: 470 | # certificate-authority-data: .... 471 | # server: https://127.0.0.1:6443 472 | # name: default 473 | # contexts: 474 | # - context: 475 | # cluster: default 476 | # user: default 477 | # name: default 478 | # current-context: default 479 | # kind: Config 480 | # preferences: {} 481 | # users: 482 | # - name: default 483 | # user: 484 | # password: ... 485 | # username: admin 486 | ``` 487 | 488 | ### 4.2.10 `kubectl` 명령 치트시트 489 | 490 | [https://kubernetes.io/docs/reference/kubectl/cheatsheet/](https://kubernetes.io/docs/reference/kubectl/cheatsheet/) 491 | 492 | ### Clean Up 493 | 494 | ```bash 495 | kubectl delete pod --all 496 | ``` -------------------------------------------------------------------------------- /chapters/04/mynginx.yaml: -------------------------------------------------------------------------------- 1 | # mynginx.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: mynginx 6 | spec: 7 | containers: 8 | - name: mynginx 9 | image: nginx -------------------------------------------------------------------------------- /chapters/05/cmd.yaml: -------------------------------------------------------------------------------- 1 | # cmd.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: cmd 6 | spec: 7 | restartPolicy: OnFailure 8 | containers: 9 | - name: nginx 10 | image: nginx 11 | # 실행명령 12 | command: ["/bin/echo"] 13 | # 파라미터 14 | args: ["hello"] -------------------------------------------------------------------------------- /chapters/05/downward-env.yaml: -------------------------------------------------------------------------------- 1 | # downward-env.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: downward-env 6 | spec: 7 | restartPolicy: OnFailure 8 | containers: 9 | - name: downward 10 | image: k8s.gcr.io/busybox 11 | command: [ "printenv"] 12 | env: 13 | - name: NODE_NAME 14 | valueFrom: 15 | fieldRef: 16 | fieldPath: spec.nodeName 17 | - name: POD_NAME 18 | valueFrom: 19 | fieldRef: 20 | fieldPath: metadata.name 21 | - name: POD_NAMESPACE 22 | valueFrom: 23 | fieldRef: 24 | fieldPath: metadata.namespace 25 | - name: POD_IP 26 | valueFrom: 27 | fieldRef: 28 | fieldPath: status.podIP -------------------------------------------------------------------------------- /chapters/05/downward-volume.yaml: -------------------------------------------------------------------------------- 1 | # downward-volume.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: downward-volume 6 | labels: 7 | zone: ap-north-east 8 | cluster: cluster1 9 | spec: 10 | restartPolicy: OnFailure 11 | containers: 12 | - name: downward 13 | image: k8s.gcr.io/busybox 14 | command: ["sh", "-c"] 15 | args: ["cat /etc/podinfo/labels"] 16 | volumeMounts: 17 | - name: podinfo 18 | mountPath: /etc/podinfo 19 | volumes: 20 | - name: podinfo 21 | downwardAPI: 22 | items: 23 | - path: "labels" 24 | fieldRef: 25 | fieldPath: metadata.labels -------------------------------------------------------------------------------- /chapters/05/env.yaml: -------------------------------------------------------------------------------- 1 | # env.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: env 6 | spec: 7 | containers: 8 | - name: nginx 9 | image: nginx 10 | env: 11 | - name: hello 12 | value: "world!" -------------------------------------------------------------------------------- /chapters/05/game-volume.yaml: -------------------------------------------------------------------------------- 1 | # game-volume.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: game-volume 6 | spec: 7 | restartPolicy: OnFailure 8 | containers: 9 | - name: game-volume 10 | image: k8s.gcr.io/busybox 11 | command: [ "/bin/sh", "-c", "cat /etc/config/game.properties" ] 12 | volumeMounts: 13 | - name: game-volume 14 | mountPath: /etc/config 15 | volumes: 16 | - name: game-volume 17 | configMap: 18 | name: game-config -------------------------------------------------------------------------------- /chapters/05/game.properties: -------------------------------------------------------------------------------- 1 | # game.properties 2 | weapon=gun 3 | health=3 4 | potion=5 -------------------------------------------------------------------------------- /chapters/05/init-container.yaml: -------------------------------------------------------------------------------- 1 | # init-container.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: init-container 6 | spec: 7 | restartPolicy: OnFailure 8 | containers: 9 | - name: busybox 10 | image: k8s.gcr.io/busybox 11 | command: [ "ls" ] 12 | args: [ "/tmp/moby" ] 13 | volumeMounts: 14 | - name: workdir 15 | mountPath: /tmp 16 | initContainers: 17 | - name: git 18 | image: alpine/git 19 | command: ["sh"] 20 | args: 21 | - "-c" 22 | - "git clone https://github.com/moby/moby.git /tmp/moby" 23 | volumeMounts: 24 | - name: workdir 25 | mountPath: "/tmp" 26 | volumes: 27 | - name: workdir 28 | emptyDir: {} -------------------------------------------------------------------------------- /chapters/05/limits.yaml: -------------------------------------------------------------------------------- 1 | # limits.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: limits 6 | spec: 7 | restartPolicy: OnFailure 8 | containers: 9 | - name: mynginx 10 | image: python:3.7 11 | command: [ "python" ] 12 | args: [ "-c", "arr = []\nwhile True: arr.append(range(1000))" ] 13 | resources: 14 | limits: 15 | cpu: "500m" 16 | memory: "1Gi" -------------------------------------------------------------------------------- /chapters/05/liveness.yaml: -------------------------------------------------------------------------------- 1 | # liveness.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: liveness 6 | spec: 7 | containers: 8 | - name: nginx 9 | image: nginx 10 | livenessProbe: 11 | httpGet: 12 | path: /live 13 | port: 80 -------------------------------------------------------------------------------- /chapters/05/monster-config.yaml: -------------------------------------------------------------------------------- 1 | # monster-config.yaml 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: monster-config 6 | namespace: default 7 | data: 8 | monsterType: fire 9 | monsterNum: "5" 10 | monsterLife: "3" -------------------------------------------------------------------------------- /chapters/05/monster-env.yaml: -------------------------------------------------------------------------------- 1 | # monster-env.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: monster-env 6 | spec: 7 | restartPolicy: OnFailure 8 | containers: 9 | - name: monster-env 10 | image: k8s.gcr.io/busybox 11 | command: [ "printenv" ] 12 | # env 대신에 envFrom 사용 13 | envFrom: 14 | - configMapRef: 15 | name: monster-config -------------------------------------------------------------------------------- /chapters/05/mynginx.yaml: -------------------------------------------------------------------------------- 1 | # mynginx.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | labels: 6 | run: mynginx 7 | name: mynginx 8 | spec: 9 | containers: 10 | - image: nginx 11 | name: mynginx 12 | restartPolicy: Never -------------------------------------------------------------------------------- /chapters/05/node-selector.yaml: -------------------------------------------------------------------------------- 1 | # node-selector.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: node-selector 6 | spec: 7 | containers: 8 | - name: nginx 9 | image: nginx 10 | # 특정 노드 라벨 선택 11 | nodeSelector: 12 | disktype: ssd -------------------------------------------------------------------------------- /chapters/05/readiness-cmd.yaml: -------------------------------------------------------------------------------- 1 | # readiness-cmd.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: readiness-cmd 6 | spec: 7 | containers: 8 | - name: nginx 9 | image: nginx 10 | readinessProbe: 11 | exec: 12 | command: 13 | - cat 14 | - /tmp/ready -------------------------------------------------------------------------------- /chapters/05/readiness.yaml: -------------------------------------------------------------------------------- 1 | # readiness.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: readiness 6 | spec: 7 | containers: 8 | - name: nginx 9 | image: nginx 10 | readinessProbe: 11 | httpGet: 12 | path: /ready 13 | port: 80 -------------------------------------------------------------------------------- /chapters/05/requests.yaml: -------------------------------------------------------------------------------- 1 | # requests.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: requests 6 | spec: 7 | containers: 8 | - name: nginx 9 | image: nginx 10 | resources: 11 | requests: 12 | cpu: "250m" 13 | memory: "500Mi" -------------------------------------------------------------------------------- /chapters/05/resources.yaml: -------------------------------------------------------------------------------- 1 | # resources.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: resources 6 | spec: 7 | containers: 8 | - name: nginx 9 | image: nginx 10 | resources: 11 | requests: 12 | cpu: "250m" 13 | memory: "500Mi" 14 | limits: 15 | cpu: "500m" 16 | memory: "1Gi" -------------------------------------------------------------------------------- /chapters/05/second.yaml: -------------------------------------------------------------------------------- 1 | # second.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: second 6 | spec: 7 | containers: 8 | - name: nginx 9 | image: nginx 10 | - name: curl 11 | image: curlimages/curl 12 | command: ["/bin/sh"] 13 | args: ["-c", "while true; do sleep 5; curl -s localhost; done"] -------------------------------------------------------------------------------- /chapters/05/secret-env.yaml: -------------------------------------------------------------------------------- 1 | # secret-env.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: secret-env 6 | spec: 7 | restartPolicy: OnFailure 8 | containers: 9 | - name: secret-env 10 | image: k8s.gcr.io/busybox 11 | command: [ "printenv" ] 12 | env: 13 | - name: USERNAME 14 | valueFrom: 15 | secretKeyRef: 16 | name: user-info 17 | key: username 18 | - name: PASSWORD 19 | valueFrom: 20 | secretKeyRef: 21 | name: user-info 22 | key: password -------------------------------------------------------------------------------- /chapters/05/secret-envfrom.yaml: -------------------------------------------------------------------------------- 1 | # secret-envfrom.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: secret-envfrom 6 | spec: 7 | restartPolicy: OnFailure 8 | containers: 9 | - name: secret-envfrom 10 | image: k8s.gcr.io/busybox 11 | command: [ "printenv" ] 12 | envFrom: 13 | - secretRef: 14 | name: user-info -------------------------------------------------------------------------------- /chapters/05/secret-volume.yaml: -------------------------------------------------------------------------------- 1 | # secret-volume.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: secret-volume 6 | spec: 7 | restartPolicy: OnFailure 8 | containers: 9 | - name: secret-volume 10 | image: k8s.gcr.io/busybox 11 | command: [ "sh" ] 12 | args: ["-c", "ls /secret; cat /secret/username"] 13 | volumeMounts: 14 | - name: secret 15 | mountPath: "/secret" 16 | volumes: 17 | - name: secret 18 | secret: 19 | secretName: user-info -------------------------------------------------------------------------------- /chapters/05/special-env.yaml: -------------------------------------------------------------------------------- 1 | # special-env.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: special-env 6 | spec: 7 | restartPolicy: OnFailure 8 | containers: 9 | - name: special-env 10 | image: k8s.gcr.io/busybox 11 | command: [ "printenv" ] 12 | args: [ "special_env" ] 13 | env: 14 | - name: special_env 15 | valueFrom: 16 | configMapKeyRef: 17 | name: special-config 18 | key: special.power -------------------------------------------------------------------------------- /chapters/05/user-info-stringdata.yaml: -------------------------------------------------------------------------------- 1 | # user-info-stringdata.yaml 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: user-info-stringdata 6 | type: Opaque 7 | stringData: 8 | username: admin 9 | password: password123 -------------------------------------------------------------------------------- /chapters/05/user-info.properties: -------------------------------------------------------------------------------- 1 | # user-info.properties 2 | username=admin 3 | password=password123 -------------------------------------------------------------------------------- /chapters/05/user-info.yaml: -------------------------------------------------------------------------------- 1 | # user-info.yaml 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: user-info 6 | type: Opaque 7 | data: 8 | username: YWRtaW4= # admin 9 | password: cGFzc3dvcmQxMjM= # password123 -------------------------------------------------------------------------------- /chapters/05/volume-empty.yaml: -------------------------------------------------------------------------------- 1 | # volume-empty.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: volume-empty 6 | spec: 7 | containers: 8 | - name: nginx 9 | image: nginx 10 | volumeMounts: 11 | - mountPath: /container-volume 12 | name: my-volume 13 | volumes: 14 | - name: my-volume 15 | emptyDir: {} -------------------------------------------------------------------------------- /chapters/05/volume.yaml: -------------------------------------------------------------------------------- 1 | # volume.yaml 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: volume 6 | spec: 7 | containers: 8 | - name: nginx 9 | image: nginx 10 | 11 | # 컨테이너 내부의 연결 위치 지정 12 | volumeMounts: 13 | - mountPath: /container-volume 14 | name: my-volume 15 | 16 | # host 서버의 연결 위치 지정 17 | volumes: 18 | - name: my-volume 19 | hostPath: 20 | path: /home -------------------------------------------------------------------------------- /chapters/06/README.md: -------------------------------------------------------------------------------- 1 | # 6. 쿠버네티스 네트워킹 2 | 3 | ## 6.1 Service 소개 4 | 5 | ```bash 6 | kubectl run mynginx --image nginx 7 | # pod/mynginx created 8 | 9 | # Pod IP는 사용자마다 다릅니다. 10 | kubectl get pod -owide 11 | # NAME READY STATUS RESTARTS AGE IP NODE ... 12 | # mynginx 1/1 Running 0 12d 10.42.0.26 master ... 13 | 14 | kubectl exec mynginx -- curl -s 10.42.0.26 15 | # 16 | # 17 | # Welcome to nginx! 18 | #