쿠버네티스
네임스페이스
- 클러스터 안에 가상 클러스터를 또 다시 만들수 있다.
- 가상 클러스터를 네임스페이라고 한다.
- 클러스터를 처음 구축시 default, docker, kube-public, kube-system 네임스페이스 4개가 이미 만들어져 있다.
kubectl get namespace
- 네임스페이스는 개발팀이 일정 규모 이상일때 유용하다.
- 개발자마다 자신만의 네임스페이스를 두면 메인 네임스페이스가 어질러지는 것을 방지할 수 있다.
- 네임스페이스마다 권한을 설정할 수 있으므로 견고하고 세세한 권한을 제어할 수 있다.
파드
- 컨테이너가 모인 집합체의 단위로, 적어도 하나 이상의 컨테이너로 이루어진다.
- 도커와 함께 사용한다면 파드는 컨테이너 하나 혹은 컨테이너의 집합체가 된다.
---Pod---------------------
| ContainerA, ContainerB |
--------------------------
파드 생성 및 배포
- nginx-proxy, echo app 애플리케이션, 2개의 컨테이너를 포함하는 파드를 쿠버네티스 환경에 배포
- 파드 생성은 kubectl만 사용해도 된다.
- 버전 관리 관점으로 yaml 파일을 사용하는 것이 좋다.
simple-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: simple-pod
spec:
containers:
- name: nginx
image: gihyodocker/nginx:latest
env:
- name: BACKEND_HOST
value: localhost:8090
ports:
- containerPort: 80
- name: echo
image: gihyodocker/echo:latest
ports:
- containerPort: 8090
kubectl apply -f simple-pod.yaml
파드 다루기
kubectl get pod
컨테이너 안에 접근
kubectl exec -it simple-pod sh -c nginx
- c옵션에 컨테이너명을 지정
파드안에 컨테이너의 표준 출력
kubectl logs -f simple-pod -c echo
파드 삭제
kubectl delete pod simple-pod
kubectl delete -f simple-pod.yaml
레플리카 세트
- 파드를 정의한 매니페스트 파일로는 파드를 하나밖에 생성할 수 없다.
- 어느정도 규모가 되는 애플리케이션을 구축하려면 같은 파드를 여러개 실행해 가용성을 확보해야 하는경우 레플리카 세트를 사용한다.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: echo
labels:
app: echo
spec:
replicas: 3
selector:
matchLabels:
app: echo
template: # template 아래 파드 리소스 정의와 같음
metadata:
labels:
app: echo
spec:
containers:
- name: nginx
image: gihyodocker/nginx:latest
env:
- name: BACKEND_HOST
value: localhost:8090
ports:
- containerPort: 80
- name: echo
image: gihyodocker/echo:latest
ports:
- containerPort: 8090
- replicas는 레플리카세트에서 만들 파드의 복제본 수를 의미한다.
- template 속성의 내용은 파드 정의와 같다.
kubectl apply -f simple-replicaset.yaml
kubectl get pod
- 레플리카세트를 조작해 파드의 수를 줄이면 줄인 개수만큼 파드가 삭제된다.
- 삭제된 파드는 복원할수 없기 때문에 애플리케이션 같은 무상태 파드를 사용하기에 유리하다.
디플로이먼트
- 레플리카세트보다 상위에 해당하는 리소스로 디플로이먼트가 있다.
- 디플로이먼트는 애플리케이션 배포의 기본 단위가 되는 리소드다.
- 레플리카세트는 똑같은 파드의 레플리케이션 개수를 관리 및 제어하는 리소스인데 비해, 디플로이먼트는 레플리카세트를 관리하고 다루기 위한 리소스다.
Deployment --> ReplicaSet ---> Pod
echo echo-1 echo-1a
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo
labels:
app: echo
spec:
replicas: 3
selector:
matchLabels:
app: echo
template: # template 아래 파드 리소스 정의와 같음
metadata:
labels:
app: echo
spec:
containers:
- name: nginx
image: gihyodocker/nginx:latest
env:
- name: BACKEND_HOST
value: localhost:8090
ports:
- containerPort: 80
- name: echo
image: gihyodocker/echo:latest
ports:
- containerPort: 8090
- 디플로이먼트가 레플리카세트의 리비전 관리를 할 수 있다.
kubectl apply -f simple-deployment.yaml --record
--record kubectl 명령을 실행했는지 기록을 남기는 옵션
kubectl get pod,replicas,deployment --selector app=echo
디플로이먼트의 리비전확인
kubectl rollout history deployment echo
레플리카세트의 생애주기
- 쿠버네티스는 디플로이먼트를 단위로 애플리케이션을 배포한다.
- 실제 운영에서는 레플리카세트를 직접 다루기보다는 디플로이먼트 매니페스트 파일을 통해 다루는 경우가 대부분
- 파드 개수만 수정하면 레플리카세트가 새로 생성되지 않음
- 컨테이너 이미지가 수정된 경우 새로운 파드가 생성되고 기존 파드는 단계적으로 정지된다.
롤백실행
리비전 번호 확인
kubectl rollout history deployment echo --revision=1
undo 실행으로 직전 리비전으로 롤백
kubectl rollout undo deployment echo
- 최신 디플로이먼트에 문제가 있을 경우 곧바로 이전 버전으로 돌아갈 수 있으며, 애플리케이션의 이전 버전의 동작을 확인하려는 경우에 활용할 수 있다.
서비스
- 클러스터안에서 파드의 집합(주로 레플리카세트)에 대한 경로나 서비스 디스커버리를 제공하는 리소스다.
- 서비스의 대상이 되는 파드는 서비스에서 정의하는 레이블 셀렉터로 정해진다.
simple-replicaset-with-labels.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: echo-spring
labels:
app: echo
release: spring
spec:
replicas: 1
selector:
matchLabels:
app: echo
release: spring
template: # template 아래 파드 리소스 정의와 같음
metadata:
labels:
app: echo
release: spring
spec:
containers:
- name: nginx
image: gihyodocker/nginx:latest
env:
- name: BACKEND_HOST
value: localhost:8080
ports:
- containerPort: 80
- name: echo
image: gihyodocker/echo:latest
ports:
- containerPort: 8080
---
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: echo-summer
labels:
app: echo
release: summer
spec:
replicas: 1
selector:
matchLabels:
app: echo
release: summer
template: # template 아래 파드 리소스 정의와 같음
metadata:
labels:
app: echo
release: summer
spec:
containers:
- name: nginx
image: gihyodocker/nginx:latest
env:
- name: BACKEND_HOST
value: localhost:8080
ports:
- containerPort: 80
- name: echo
image: gihyodocker/echo:latest
ports:
- containerPort: 8080
kubectl apply -f simple-replicaset-with-labels.yaml
kubectl get pod -l app=echo -l release=spring
kubectl get pod -l app=echo -l release=summer
release=summer인 파드만 접근할수 있는 서비스를 생성
apiVersion: v1
kind: Service
metadata:
name: echo
spec:
selector:
app: echo
release: summer
ports:
- name: http
port: 80
http://echo/ --------> service(name=echo) -----> Pod app=echo release = summer
app= -----> Pod app=echo release = summer
release=summer --x--> Pod app=echo release = spring
http:80
kubectl apply -f simple-service.yaml
kubectl get svc echo
release=summer인 파드에만 트래픽 전달 확인
kubectl run -i --rm --tty debug --image=gihyodocker/fundamental:0.1.0 --restart=Naver -- bash -il
curl http://echo/
서비스의 네임 레졸루션
- 쿠버네티스 클러스터의 DNS는 서비스를 서비스명.네임스페이스.svc.local로 연결해준다.
- echo는 default 네임스페이스인 경우
curl http://echo.default.svc.local
curl http://echo.default
같은 네임스페이스라면 서비스명으로만 참조가 가능
curl http://echo
ClusterIP 서비스
- 서비스에도 여러가지 종류가 있어서 그 종류를 yaml파일에서 지정할 수 있다. 기본값은 ClusterIP 서비스다.
- ClusterIP를 사용하면 쿠버네티스 클러스터의 내부 IP 주소에 서비스를 공개할 수 있다.
- 이를 이용해 어떤 파드에서 다른 파드 그룹으로 접근할 때 서비스를 거쳐가도록 할 수 있으며, 서비스명으로 네임 레졸루션이 가능해진다.
- 다만, 외부로부터 접근할 수 없다.
NodePort 서비스
- NodePort 서비스는 클러스터 외부에서 접근할 수 있는 서비스다.
- NodePort 서비스는 ClusterIP를 만든다는 점은 ClusterIP 서비스와 같다.
- 각 노드에서 서비스 포트로 접속하기 위한 글로벌 포트를 개방한다는 점이 차이점
apiVersion: v1
kind: Service
metadata:
name: echo
spec:
selector:
type: NodePort
app: echo
ports:
- name: http
port: 80
- NodePort 서비스를 생성했다면 80:31058/TCP라고 나왔듯이 노드의 포트 31058를 통해 서비스에 접근할 수 있다.
kubectl get svc echo
LoadBalancer 서비스
- 로컬 쿠버네티스 환경에서는 사용할 수 없는 서비스다.
- 이 서비스로는 주로 각 클라우드 플랫폼에서 제공하는 로드밸런서와 연동하기 위해 사용된다.
ExternalName 서비스
- 셀렉터도 포트 정의도 없는 상당히 특이한 서비스다.
- 쿠버네티스 클러스터에서 외부 호스트를 네임 레졸루션하기 위한 제공한다.
apiVersion: v1
kind: Service
metadata:
name: echo
spec:
selector:
type: ExternalName
externalName: gihyo.jp
인그레이스
- 쿠버네티스 클러스터 외부로 서비스를 공개하려면 서비스를 NodePort로 노출시킨다.
- 그러나 이방법은 L4 레벨까지만 다루기 때문에 HTTP/HTTPS 처럼 경로를 기반으로 서비스를 전환하는 L7 레벨의 제어는 불가능하다.
- 이를 해결하기 위한 리소스가 인그레이스다.
- 쿠버네티스 외부에 대한 노출과 가상 호스트 및 경로 기반의 정교한 HTTP 라우팅을 양립시킬 수 있다.
- HTTP/HTTPS 서비스를 노출하려는 경우 인그레이스를 사용한다.
- 로컬 쿠버네티스 환경에서는 인그레이스를 사용해 서비스를 노출시킬수 없다.
- 클러스터 외부에서 온 HTTP 요청을 서비스로 라우팅하기 위한 nginx_ingress_controller 배포한다.
kubectl apply -f https://raw.githubusercontent.com/~~~/mandatory.yaml
kubectl apply -f https://raw.githubusercontent.com/~~~/cloud-generic.yaml
네임스페이스 ingress-nginx에 서비스와 파드가 생성된다.
kubectl -n ingress-nginx get service,pod
인그레스를 통해 접근하기
- 실제로 인그레스를 통해 서비스에 접근
- spec.type 값을 지정하지 않으면 ClusterIP 서비스가 생성된다.
apiVersion: v1
kind: Service
metadata:
name: echo
spec:
selector:
app: echo
ports:
- name: http
port: 80
kubectl apply -f simple-service.yaml
simple-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: echo
spec:
rules:
- host: ch05.gihyo.local
http:
paths:
- path: /
backend:
serviceName: echo
servicePort: 80
kubectl apply -f simple-ingress.yaml
kubectl get ingress
- 인그레스는 L7 라우팅이 가능하므로 가상 호스팅 기능처럼 지정된 호스트 혹은 경로와 일치하는 서비스로 요청을 전달할 수 있다.
curl http://localhost -H 'Host: ch05.gihyo.local' - 인그레스 층에서 HTTP 요청에 다양한 제어를 할수 있다.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: echo
annotations:
nginx.ingress.kubernetes.io/server-snippet: |
set $agentflag 0;
if ($http_user_agent ~* "(Mobile)") {
set $agentflag 1;
}
if ($agentflag = 1) {
return 301 http://gihyo.jp/;
}
spec:
rules:
- host: ch05.gihyo.local
http:
paths:
- path: /
backend:
serviceName: echo
servicePort: 80
- 로컬 쿠버네티스 환경에서는 nginx-ingress-controller를 사용한다.
- metadata.annotations 파일에 nginx-ingress-controller 자체의 제어 설정을 할 수 있다.
- nginx.ingress.kubernetes.io/server-snippet 설정하면 Nginx 설정 파일 문법에 따라 요청 필터링 등을 사이에 추가할 수 있다.
- User-Agent 값에 Mobile이 포함되는 경우 요청을 다른 URL로 리다이렉트가 된다.
curl http://localhost
-H 'Host: ch05.gihyo.local'
-H 'User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X)a AppleWebKit/604.13 (KHTML, like Geccko) Version/11.0 Mobile/15A372 Safari/604.1'
- 요청 제어를 인그레이스에서 처리할 수 있기 때문에 백엔드나 웹서버, 애플리케이션 서버에서 이를 신경쓸 필요가 없다.
- nginx-ingress-controller는 이외에도 다양한 기능을 갖추고 있다.
- 퍼블릭 클라우드 환경에서 인그레이스는 해당 플랫폼의 L7 로드 밸런서를 이용할 수 있다.
freshpod로 이미지 업데이트 탐지하고 파드 자동 업데이트 하기
- freshpod는 쿠버네티스로 배포된 컨테이너의 이미지가 업데이트 됐는지 탐지해 파드를 자동으로 다시 배포하는 도구다.
- freshpod는 애초 Minikube의 애드온으로 개발된 것이지만 윈도우/Mac 도커에서도 사용할 수 있으므로 로컬 쿠버네티스 개발 환경에서 빼놓을 수 없는 도구다.
freshpod를 설치하려면 Minikube 리포지토리에 공개된 매니페스트 파일을 적용하면된다.
kubectl apply -f https://raw.githubusercontent.com/kubernetes/minikube/master/deploy/addons/freshpod/freshpod-rc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template: # template 아래 파드 리소스 정의와 같음
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: ch04/nginx:latest
imagePullPolicy: IfNotPresent
env:
- name: BACKEND_HOST
value: 127.0.0.1:8080
ports:
- containerPort: 80
- name: echo
image: gihyodocker/echo:latest
ports:
- containerPort: 8090
freshpod로 컨테이너를 업데이트 하려면 imagePullPolicy를 Always(파드를 재시작할때마다 항상 최신 이미지를 받아옴)가 아니라 IfNotPresent(전에 받아둔 이미지가 있으면 재사용)으로 설정해야 한다.
이미지를 수정하기 전에 -w 옵션을 사용해 파드의 실행상태를 모니터링 한다.
kubectl get pod -l app=nginx -w
그리고 ch04/nginx 이미지를 아무것이나 수정한 다음. 이미지를 빌드한다.
docker image build -t ch04/nginx:latest .
새로운 이미지가 만들어지자마자 해당 파드가 교체되기 시작한다.
- 로컬 쿠버네티스 환경에서 freshpod를 사용하면 새로 만든 이미지를 매번 레지스트리에 등록하거나 직접 파드를 업데이트 하지 않아도 되기 때문에 효율적인 개발이 된다.
kube-prompt
- 쿠버네티스 리소스를 다루기 위한 명령행 도구로 kubectl이 있지만 편의성이 개선된 도구가 있다.
- kube-prompt는 kubectl 명령 및 리소스 이름의 자동완성 기능을 제공한다.
- macOS/리눅스용 이다.
쿠버네티스 API
- 매니페스트 파일의 apiVersion 필드의 값이 리소스 종류에 따라 달라진다.
- 쿠버네티스 리소스를 생성, 수정, 삭제하는 작업은 쿠버네티스 클러스터에 배포된 API가 수행한다.
- 여러 API를 하나로 묶은 형태로 구성되는데, 이 apiVersion은 해당 작업에 사용되는 API 종류를 나타내는 값이다.
kubectl api-versions
- 쿠버네티스의 리소스가 각각 어떤 API를 통해 지원되는지 알고 있다면 쿠버네티스 API 리포지토리를 확인한다.
도커/쿠버네티스를 활용한 컨테이너 개발 실전 입문
야마다 아키노리 지음 / ㅣ심효섭 옮김