용찬호. 「 시작하세요! 도커/쿠버네티스」. 위키북스 를 읽으며, 학습한 내용을 정리하는 글입니다.
→ 본문의 내용은 모두 책의 내용에 대한 직/간접적 인용임을 밝힙니다.
[ 개발 용도의 쿠버네티스 설치 ]
[ 서비스 테스트 또는 운영 용도의 쿠버네티스 설치 ]
→ Preference -> Enable Kubernetes 클릭!
→ kubectl version --short
명령어 입력하여
쿠버네티스 정상 설치 확인!
Minikube는 로컬에서 가상 머신이나 도커 엔진을 통해 쿠버네티스를 사용할 수 있는 환경을 제공
→ Minikube는 가상 머신 또는 도커를 통해 쿠버네티스를 설치하기 때문에, 버추얼 박스
또는 도커 엔진
이 미리 설치되어 있어야 한다.
[ 기본 설정을 이용해 버추얼 박스로 minikube 설치 ]
1. 버추얼박스 설치
apt-get install virtualbox
-> 가상화 도구 설치 (in Linux!)minikube \
https://storage.googleapis.com/minikube/releases/v1.4.0/minikube-linux-amd64 && \
chmod +x minikube && \
sudo mv minikube /usr/local/bin/
minikube start
kubeadm
[ example ]
kube-master1 172.30.0.100
kube-worker1 172.31.0.101
kube-worker2 172.31.0.102
kube-worker3 172.31.0.103
1. 쿠버네티스 저장소 추가
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpt | apt-key add -
cat <<EOR > /etc/apt/sources.list.d/kubernetes.list
2. kubeadm 설치 wget -q0- get.docker.com | sh
apt-get install -y kubelet kubeadm kubectl kubernetes-cni
3. 쿠버네티스 클러스터 초기화
마스터 노드
로 사용할 호스트에서 다음 명령어로 클러스터를 초기화!
kubeadm init --apiserver-advertise-address 172.31.0.100 \ --pod-network-cidr=192.168.0.0/16
apiserver-advertise-address
옵션의 인자에, 다른 노드가 마서트에게 접근할 수 있는 IP 주소를 환경에 맞게 입력
--pod-network-cidr
은 쿠버네티스에서 사용할 컨테이너의 네트워크 대역이며, 각 서버의 네트워크 대역과 중복되지 않게 설정 필요!
→ Your Kubernetes control-plane has initialized successfully!
메시지 확인~!
→ 중간에 표시되는 명령어 3줄을 복사하여 마스터 노드에서 실행함!
→ 마지막에 출력된 명령어인 kubeadm join...
은 마스터를 제외한 노드인 워커 노드에서 실행한다.
4. 컨테이너 네트워크 애드온 설치
flannel
, weaveNet
등 여러 오버레이 네트워크의 사용이 가능calico
를 기준으로 함!kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/calico.yml
kubectl get pods --namespace kube-system
kops는 클라우드 플랫폼에서 쉽게 쿠버네티스 설치를 할 수 있게 하는 도구
→ AWS, GCP 등의 클라우드 플랫폼에서 설치를 지원
→ 2019년 10월을 기준으로 kops는 AWS만을 공식 지원!
1. kops 및 kubectl 실행 바이너리 내려받기
wget -O kops https://github.com/kubernetes/kops/releases/download/1.12.3/kops-linux-amd64
chmod _x ./kops
sudo mv ./kops /usr/local/bin
wget -O kubectl \
http://storage.googleapis.com/kubernetes-release/release/v1.14.0/bin/linux/amd64/kubectl
chmod +x kubectl
sudo mv kubectl /sr/local/bin
2. AWS 사용자 생성, 정책 연결 및 AWS CLI 설정
3. S3 버킷에 쿠버네티스 클러스터의 설정 정보 저장
# 버킷 생성
aws s3api create-bucket \
--bucket alicek106-k8s-bucket \
--create-bucket-configuration LocaationConstraint=ap-northeast-2
# S3 버킷의 버저닝을 기록
aws s3api put-bucket-versioning
--bucket alicek106-k8s-bucket \
--versioning-configuration Status=Enabled
export NAME=mycluster.k8s.local
export KOPS_STATE_STORE=s3://alicek106-k8s-bucket
ssh-keygen -t rsa -N "" -f ./id_rsa
kops create cluster \
--zones ap-northeast-2a \
--networking calico \
--ssh-public-key ./id_rsa.pub \
$NAME
4. 쿠버네티스 클러스터 옵션 변경
워커 노드의 옵션 수정
kops edit ig nodes --name $NAME
노드의 개수는 maxSize와 minSize를 수정해 변경하며, 워커의 CPU와 메모리 크기는 인스턴스 타입을 수정해 변경한다.
apiVersion: kops/v1alpha2
kind: InstanceGroup
spec:
image: kope.io/k8s-1.11-debian-stretch-amd64-hvm-ebs-2018-08-17
machineType: t2.medium
maxSize: 3
minSize: 3
마스터 노드의 설정을 변경!
kops edit ig master-ap-northeast-2a --name $NAME
apiVersion: kops/v1alpha2
kind: InstanceGroup
spec:
image: kope.io/k8s-1.11-debian-stretch-amd64-hvm-ebs-2018-08-17
machineType: t2.medium
maxSize: 1
5. 쿠버네티스 클러스터 생성
아래 명령어를 입력하면 kops가 자동으로 서버 인스턴스, 네트워크 리소스 등을 생성해 쿠버네티스를 설치!
kops update cluster --yes $NAME
kops validate cluster
명령어로 쿠버네티스 설치 진행 상황 확인kubectl get nodes
로 노드의 목록, 쿠버네티스 버전을 출력해 정상 설치 확인!kubectl api-resources
명령어로 쿠버네티스에서 사용 가능한 오브젝트 확인 가능!kubectl
명령어로 쿠버네티스 사용 가능!→ 컴포넌트들은 기본적으로 도커 컨테이너로서 실행된다!
→ 쿠버네티스 클러스트 구성을 위해 kubelet
이라는 에이전트가 모든 노드에서 실행!
= 컨테이너의 생성, 삭제뿐만 아니라 마스터와 워커 노드 간의 통신 역할을 담당하는 중요한 에이전트이다!
포드(Pod)
라고 부른다!ex) Nginx 컨테이너로 구성된 포드
apiVersion: v1
kind: Pod
metadata:
name: my-nginx-pod
spec:
containers:
- name: my-nginx-container
image: nginx:latest
ports:
- containerPort: 80
protocol: TCP
apiVersion
: YAML 파일에서 정의한 오브젝트의 API 버전kind
: 리소스의 종류. 위의 YAML 파일에서 생성하려고 하는 것이 포드이므로 Pod를 입력metadata
: 라벨, 주석(Annotation), 이름 등과 같은 리소스의 부가 정보 입력spec
: 리소스를 생성하기 위한 자세한 정보를 입력→ YAML 파일은 kubectl apply -f
명령어로 쿠버네티스에 생성한다.
= 새로운 포드 생성!
kubectl apply -f nginx-pod.yaml
kubectl describe pods my-nginx-pod
→ docker run 명령어에서 -p 옵션 없이 실행한 것과 유사!
클러스터의 노드 중 하나에 접속하여, Nginx 포드의 IP로 HTTP 요청을 전송하여 Nginx 포드가 정상 실행 중인 것을 알 수 있다.
docker exec와 비슷하게, kubectl exec
명령어로 포드의 컨테이너에 명령어 전달이 가능하다.
kubectl exec -it my-nginx-pod bash
→ 여기까지만 놓고 보면, 포드는 docker run으로 생성한 단일 nginx 컨테이너와 유사하다?
kubectl exec
명령어로 포드 컨테이너 내부로 들어갈 수도 있음kubectl logs
명령어로 포드의 로그 확인도 가능!→ 그렇다면 쿠버네티스는 왜, '도커 컨테이너'가 아니라 '포드'라는 새로운 개념을 사용하는가?
→ 여러 리눅스 네임스페이스(namespace)를 공유하는 여러 컨테이너들을 추상화된 집합으로 사용하기 위함-!
→ 이 설명을 조금 더 자세히 알아보자-!
apiVersion: v1
kind: Pod
metadata:
name: my-nginx-pod
spec:
containers:
- name: my-nginx-container
image: nginx:latest
ports:
- containerPort: 80
protocol: TCP
- name: ubuntu-sidecar-container
image: alicek106/rr-test:curl
command: ["tail"]
args: ["-f", "/dev/null"] # 컨테이너가 종료되지 않도록 유지
kubectl apply -f nginx-pod-with-ubuntu.yml # 적용
kubectl exec -it my-nginx-pod -c ubuntu-sidecar-container bash # 특정 컨테이너에서 배시 셸 실행
하나의 포드는 하나의 완전한 애플리케이션이다.
→ 포드에 정의된 여러 개의 컨테이너는 하나의 완전한 애플리케이션으로서 동작한다.
→ 이게 도커 컨테이너와 쿠버네티스 포드의 차이점!
쿠버네티스의 기본 단위인 포드는 여러 개의 컨테이너를 추상화해, 하나의 애플리케이션으로 동작하도록 만드는 컨테이너 묶음
apiVersion: apps/v1 # 레플리카셋 정의
kind: ReplicaSet
metadata:
name: replicaset-nginx
spec:
replicas: 3 # 동일한 포드를 몇 개 유지할지 설정
selector:
matchLabels:
app: my-nginx-pods-label
template: # 포드 생성시 사용할 템플릿 정의
metadata:
name: my-nginx-pod
labels:
app: my-nginx-pods-label
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
실제로 레플리카셋은 포드와 연결돼 있지 않음
포드 생성시, metadata 항목에서는 리소스의 고유 이름, 라벨 등 부가적인 정보를 설정할 수 있었다.
라벨은 서로 다른 오브젝트가 서로를 찾아야 할 때도 쓰인다.
spec.selector.matchLabel
에 정의된 라벨을 통해 생성해야 하는 포드를 찾는다. 레플리카셋의 목적은 '포드를 생성하는 것'이 아니라 '일정 개수의 포드를 유지하는 것'이다.
+) 레플리카셋의 selector.matchLabel 항목처럼, 두 리소스 간의 라벨을 일치시킴으로써 쿠버네티스의 기능을 사용하는 경우가 많다!
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: my-nginx
template:
metadata:
name: my-nginx-pod
labels:
app: my-nginx
spec:
containers:
- name: nginx
image: nginx:1.10
ports:
- containerPort: 80
애플리케이션의 업데이트와 배포를 더욱 편하게 만들기 위함!
[ ex. 포드의 이미지 버전을 nginx:1.11로 변경하기 ]
kubectl set image deployment my-nginx-deployment nginx=nginx:1.11 --record
→ 이렇게 실행하면, 레플리카셋의 목록이 2개가 된다!
→ 디플로이먼트는 포드의 정보를 업데이트함으로써 새로운 레플리카셋과 포드를 생성했음에도 불구하고, 이전 버전의 레플리카셋을 삭제하지 않고 남겨둔다.
도커 컨테이너와 마찬가지로 포드의 IP는 영속적이지 않아, 변할 수 있음.
여러 개의 디플로이먼트를 하나의 완벽한 애플리케이션으로 연동하려면 포드 IP가 아닌, 서로를 발견(Discovery)할 수 있는 방법이 필요!
쿠버네티스는 디플로이먼트를 생성할 대 포드를 외부로 노출하지 않으며,
디플로이먼트의 YAML 파일에는 단지 포드의 애플리케이션이 사용할 내부 포트만 정의
[ 서비스 주요 기능 ]
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-clusterip
spec:
ports:
- name: web-port
port: 8080 # 서비스의 IP에 접근할 때 사용할 포트를 설정
targetPort: 80 # selector 항목에서 정의한 라벨에 의해 접근 대상이 된 포드들이 내부적으로 사용 중인 포트
selector: # 이 서비스에서 어떠한 라벨을 갖는 포드에 접근할 수 있게 할 것인가
app: webserver
type: ClusterIP
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-nodeport
spec:
ports:
- name: web-port
port: 8080
targetPort: 80
selector:
app: webserver
type: NodePort
NodePort 타입의 서비스인데도, kubectl get service
명령어의 출력에서 CLUSTER-IP 항목에 내부 IP도 할당된다!
이는 NodePort 타입의 서비스가 ClusterIP의 기능을 포함하고 있기 때문!
다만, 실제 운영 환경에서 NodePort로 서비스를 외부에 제공하는 경우는 많지 않다.
따라서, NodePort 서비스 그 자체를 통해 서비스를 외부로 제공하기보다는 인그레스(Ingress)라고 부르는 쿠버네티스의 오브젝트에서 간접적으로 사용함!
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-lb
spec:
ports:
- name: web-port
port: 80 # 로드밸런서에 접근하기 위한 포트
targetPort: 80
selector:
app: webserver
type: LoadBalancer
kubectl get svc hostname-svc-nodeport -o yaml
→ externalTrafficPolicy의 기본 설정값인 Cluster
는 클러스터의 모든 노드에 랜덤한 포트를 개방하는 방식
→ Local
로 설정하면, 포드가 생성된 노드에서만 포드로 접근할 수 있고, 로컬 노드에 위치한 포드 중 하나로 요청이 전달된다!
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-lb-local
spec:
externalTrafficPolicy: Local
ports:
- name: web-port
port: 80
targetPort: 80
selector:
app: webserver
type: LoadBalancer
→ 각 노드에 포드가 고르지 않게 스케줄링 됐을 때, 요청이 고르게 분산되지 않을 수도 있다.
→ Cluster와 Local 모두 장단점이 있음!