- Amazon Elastic Container Service(Amazon ECS)는 클러스터에서 Docker 컨테이너를 손쉽게 실행, 중지 및 관리할 수 있게 해주는 컨테이너 관리 서비스 이다.
- AWS(EKS, ECS=Swarm), Azure(AKS), GCP(GKE)들을 클러스터로 사용하여 멀티 클라우드로 사용해 무중단서비스, 고가용성을 지킬 수 있다.
- Task(작업, Pods)가 컨테이너를 감싸고 있다.
- 그 Task는 서비스로 묶여있고, 이 서비스들은 한 Cluster단위로 작업하게될 것이다.
작업정의 생성
- 작업정의항목을 클릭해서 새로운 작업을 정의해준다.
- EC2를 사용할 것이다.
- Cluster에게 작업 명령을 내리려면 역할(roll, 권한)이 필요한데, ECS에서 역할을 자동으로 만들어 줄 것이다.
컨테이너 추가
- 여기서
docker run
으로 생성했던 컨테이너를 미리 정의하게 된다.
- 컨테이너 이름은 docker에서 --name 옵션과 같다.
- 이미지는 버전정보를 주지 않으면 자동으로 최신버전을 사용하게 된다.
- 메모리 제한은 필수입력 정보이다.
- 하드 제한으로 128Mb를 사용함으로 세팅한다.
- 포트 매핑은 -p 옵션과 동일하며 80:80으로 설정해준다.
생성
- 컨테이너만 추가하고 생성버튼을 눌러준다.
클러스터 생성
- EC2 클러스터를 생성해준다.
클러스터 구성
- 이름: MY-CLUSTER
- 프로비저닝 모델에서 온디멘드는 가장 비싼 방법이다.
- 사용하는 시간당 비용을 지불하게 되며
- 컨테이너가 갑자기 사라질일이 없다.
- 스팟 프로비저닝은 경매를 통해 나보다 더 비싼 금액을 부른 사람이 나올때까지 인스턴스를 사용하는 방법이다.
- 스팟 인스턴스는 언제 생성되고 언제 사라질지 모른다.
- 그러나 클러스터는 작업목적에따라 다르지만, 자원을 관리할 수 있다면 매우 저렴하게 인스턴스를 사용할 수 있다.
- 지금은 온디멘드 방식으로 진행해본다.
- EC2인스턴스 유형은 자동으로 어느정도 용량이 있는 인스턴스가 사용된다.
- 아래 원하는 인스턴스 유형 직접입력으로 t2.micro를 사용해준다.
네트워킹 구성
- 기존에 만들어져있는 NEW-VPC, MY-VPC를 사용해준다.
- 서브넷은 2a, 2c를 사용한다.
- 퍼블릭 IP를 받을 수 있도록 활성화해준다.
- 보안그룹은 기존에 만들어져 있는 보안그룸을 사용한다.
- HTTP, ICMP, SSH허용
컨테이너 인스턴스 IAM역할
- 컨테이너 인스턴스 IAM역할은 아까 생성한 ECS작업으로 자동으로 고정되어있다.
생성
시작상태
- 클러스터와 인스턴스 IAM성책이 완성되었다.
- CloudFormatino이 생성중인데, 에러가난다면, 이전버튼으로 돌아가 수정하면 될 것이다.
결과 확인
- 클러스터가 잘 생성되엇따.
- 인스턴스도 생성되어 서비스 중이다.
- 현재 클러스터 화면을 확인한다.
- ECS인스턴스에 생성된 EC2인스턴스를 볼 수 있다.
- 여기서 ECS가 Master, Control plane
- EC2인스턴스가 Worker노드가 되는 것이다.
- 그러나 이 인스턴스에는 TASK가 들어가 있지 않다.
- 서비스를 생성해줘야한다.
서비스 생성
- 여기서 서비스를 생성해준다.
서비스 구성
- 시작 유형: EC2
- 작업 정의는 아까 생성한 작업을 사용해준다.
- 클러스터도 방금 생성한 클러스터
- 서비스 이름은 : MY-WEB으로 한다.
- 서비스 유형: REPLICA
- 작업 개수: 2
- 두개의 EC2노드에 2개의 작업을 부여한다.
- 즉, EC2노드 하나에 한 작업이 부여된다.
- 최소 정상 상태 백분율 : 50
- 최대 백분율 : 100
- 업데이트와 관련된 설정이다.
- 업데이트를 할 때, 구버전을 지우지않고, 신버전을 생성하녀 2-> 4개의 컨테이너가 운영되는 시점이 생긴다.
- 최소 정상 상태 백분율은 평소에 50%의 컨테이너만 생성하고, 업데이트시 최대 100%의 컨테이너를 생성한다.
- 즉 최대 2개일때, 평소 1개의 컨테이너만 사용하고, 최대 2개까지 생성하여 업데이트 한다.
배포
- 배포시에는 롤링 업데이트를 사용한다.
네트워크 구성
- 로드밸런서 유형은 ALB(Application Load Balancier)를 사용한다.
- 상태 검사 유예 기간: 150
- 인스턴스의 상태검사를 할 때, EC2가 만들어지는 중에 상태검사를 유예해주는 시간이다.
로드밸런서 생성1
대상그룹 생성
로드밸런서 생성2
다시 서비스 생성
- 여기서 방금 생성한 MY-ALB를 추가하고,
- 아래 로드 밸런서에 추가 버튼을 눌러준다.
- 프로덕션 리스너 포트 80:HTTP
- 대상그룹은 방금 생성한 대상그룹으로 선택한다.
Auto Scaling(선택사항)
자동 작업 조정 정책
- 먼저 Desired state를 먼저 생성해준다.
- ScaleOutAlarm과 Policy를 생성한다.
- 반대로 ScaleInAlarm와 Policy를 생성해준다.
서비스 접속 확인
- EC2 -> 로드밸런서 에서 DNS주소를 받아 웹브라우저로 접속해본다.
- 잘 접속되고, 잘 동작한다.
- Route53에서 등록해준다.
- 새 작업을 정의한다.
- EC2 시작유형 호환선을 선택한다.
- 컨테이너를 추가해준다.
- 컨테이너 이름은 기존과 동일한 이름으로한다.
- 이미지를 우리가 Docker HUB에서 PUSH했던 이미지를 사용한다.
작업 정의 정리
- 각 작업을 클릭해서 등록취소를 눌러준다.
- API 서버는 일종의 마스터의 역할을 한다.
- 컨트롤러를 구동하는 마스터 상의 컴포넌트
- 각 컨트롤러는 개별 프로세스지만, 복잡성을 낮추기위해 모두 단일 바이너리로 컴파일되고, 단일 프로세스내에서 실행된다.
- 이들 컨트롤러는 다음을 포함한다.
- 노드 컨트롤러 : 노드가 다운되었을 때, 통지와 대응에 관한 책임
- 레플리케이션 컨트롤러: 시스템의 모든 레플리케이션 컨트롤러 오브젝트에 대해 알맞은 수의 Pods을 유지시켜준느 책임 (replicas=5)
- 엔드포인스 컨트롤러: 엔드포인트 오브젝트를 채운다.
- 즉, 서비스와 Pods를 연결시킨다.
- 서비스 어카운트 & 토큰 컨트롤러: 새로운 네임스페이스에 대한 기본 계정과 API접근 토큰을 생성한다.
- 사용자가 권한을 가진 사용자인지 토큰을 확인할 수 있음
- 퍼블릭 클라우드에서 제공하는 하나의 컴포넌트이다.
- 클라우드 컨트롤러 매니저를 통해 클러스터를 클라우드 공급자의 API에 연결한다.
- 해당 클라우드 플랫폼과 상호작용하는 컴포넌트와 클러스터와 상호 작용하는 컴포넌트를 분리할 수 있다.
노드 컴포넌트
- 노드 컴포넌트는 동작중인 pods를 유지시키고, 쿠버네티스 런타임 환경을 제공하며, 모든 노드상에서 동작한다.
- 심지어 master노드에도 worker노드를 생성할 수 있다.
- 클러스터의 각 노드에서 실행되는 에이전트
- kubelet은 Pods에서 컨테이너가 확실하게 동작하도록 관리한다.
- ha-proxy의 기능도 가지고있다.
- 엔드 노드들이 여러 작업을 하더라도, 결국 워커노드에서 작업하게 되는데, 쿠버네티스의 서비스 개념의 구현부이다.
- kube-proxy는 노드의 네트워크 규칙을 유지 관리한다.
- 또 ,이 네트워크 규칙이 내부 네트워크 세션이나 클러스터 바깥에서 파드로 네트워크 통신을 할 수 있도록 해준다.
- 컨테이너 런타임(도커)는 컨테이너 실행을 담당하는 소프트웨어이다.
- 큐블렛을 실질적으로, Pods를 꾸미고, 그 안에 컨테이너를 생성하게 된다.
- 쿠버네티스는 여러 컨테이너 런타임을 지원한다.
- Docker, Containerd, CRI-O
- CentOS7의 ISO, CPU:2c, RAM: 4Gb의 VM을 구성한다.
- 이름: Minikube로 해준다.
- 네트워크 MAC주소를 업데이트해준다.
- 시작.
curl -fsSL https://get.docker.com/ | sudo sh
- 도커 설치, Node의 컨테이너 런타임을 설치하고잇는 것이다.
systemctl enable --now docker
yum install -y conntrack git
- conntrack과 git을 설치해준다.
curl -Lo minikube https://storage.googleapis.com/minikube/releases/v1.23.2/minikube-linux-amd64 && chmod +x minikube
- 미니큐브를 설치한다. 이때 1.23.2버전을 설치하는데, 이후 에러가 날 수 있다. 버전을 계속 수정하며 설치해봐야 한다.
- 구글에서 개발했기 때문에, 구글의 스토리지에서 가져온다.
- 또, minikube-linux-amd64라는 이름을 minikube라고 설정하며, && chmod로 실행할 수 있도록 권한을 수정한다.
- mkdir -p /usr/local/bin/
- /bin디렉토리가 없다면 만들어준다.
- install minikube /usr/local/bin/
- minikube 명령어를 /bin에 설치해준다.
- 설치확인을 위해
minikube version
을 입력해본다.minikube start --driver=none
- 간단하게 minikube를 시작한다.
- --driver를 사용하려면, 하이퍼바이저를 넣어줘야 하는데, 이러려면 VM안에 또 하이퍼바이저를 설치해야한다.
- 지정하지 않는것이 간편하다.
- minikube status
- 상태확인
curl -LO https://dl.k8s.io/release/v1.22.2/bin/linux/amd64/kubectl
- kubectl을 다운로드 받는다.
install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
- kubectl을 설치해준다.
source <(kubectl completion bash)
소스에 kubectl completion bash를 넣어준다.echo "source <(kubectl completion bash)" >> ~/.bashrc
- .bashrc에 source값을 넣어준다.
kubectl version
- 설치를 확인한다.
Cluster
- Master에서 Node들을 관리하며, 자가치유 기능을 가지고 있다.
- 노드가 정지가되면, 새로 노드를 생성하여 자가치유한다.
- 또, 노드가 정지될 때, Pod들을 다른 노드로 옮겨 무중단서비스를 이어간다.
- Master Node (Controller Node)
- Worker Node (Compute Node)
pod
- 파드(Pods) : 쿠버네티스에서 배포할 수 있는 가장 작은 단위
- 한개 이상의 컨테이너와 스토리지, 네트워크 속성을 가진다.
- pods에 속한 컨테이너는 스토리지와 네트워크를 서로 공유하고, 서로 localhost로 접근할 수 잇다.
- 도커스웜과 ECS에서는 Task라고 불렀다.
Service(서비스): 네트워크와 관련된 리소스
- Pod을 외부 네트워크와 연결해주고, 여러개의 pod을 바라보는 내부 로드 밸런서를 생성할 때 사용한다.
- 내부 DNS에 서비스 이름을 도메인으로 등록하기 때문에 서비스 디스커버리 역할도 한다.
pods 실행
mkdir workspace && $_
- 실습을 진행할 workspace 생성
kubectl run nginx-pod --image=nginx
- pod 안쪽에 nginx이미지를 사용하여, nginx-pod라는 pod를 생성했다.
--type 유형
- --type=ClusterIP : 내부에서 클러스터를 구별하는 IP, 내부에서 서로 통신할 수 있다.
- 트래픽이 클러스터로 들어올 때, 프록시 설정이 없으면 ClusterIP는 외부에서 접속이 불가능하다.
- kubeproxy를 통헤 service에 들어오고, service에서 pod로 들어간다.
- --type=NodePort: 내부에서만 연결되는 ClusterIP와 달리 외부와 연결된다.
- --type=LoadBalancer
EXPOSE
- 여기서는 Expose에 의미가 있다.
- Endpoint 서비스를 위한 포트를 열어준다.
- kubeproxy가 pod에 접속할 수 있는 네트워크 정보를 만드는 것이다.
ClusterIP 생성
kubectl expose pod nginx-pod --name clusterip --type=ClusterIP --port 80
- Clusterip를 생성했다.
- kubectl get svc로 서비스들을 본다.
- 그러나 IP주소로 접속할 수 없다.
- ClusterIP는 내부 클러스터들 간의 통신하는 IP이기 때문이다.
- 그래서 노드 안에서 curl명령어로 접속해보니 nginx가 잘 나온다.
Nodeport
kubectl expose pod nginx-pod --name nodeport --type=NodePort --port 80
- NodePort를 생성하였다.
- ClusterIP처럼 내부에서 통신하는 IP주소도 생성되면서 동시에 호스트의 IP로 포트포워딩되어 접근할 수 있는 Port도 열어준다.(31038포트가 열렸다.)
- 내부에서 curl명령어로 Nodeport IP로 접속했을 때 잘 나온다.
- 호스트IP주소에 Nodeport의 포트번호로 접속할 때, 잘 출력된다.
--type=LoadBalancer
kubectl expose pod nginx-pod --name loadbalancer --type=LoadBalancer --external-ip 192.168.0.144 --port 80
- 로드밸런서 유형을 실행해본다.
- 로드 밸런서는 ClusterIP의 내부 IP와, NodePort의 호스트IP:nodeport 를 동시에 가지고있다.
- 또, 이제 그냥 호스트IP로 들어가면 서버에 접속할 수있다.
- 이렇게 호스트IP에서 포트번호80번으로 접속할 수 있다.
- 이 ClusterIP, NodePort, LoadBalancer들을 서로 포트가 충돌하지 않는다.
생성된 서비스 보기
- kubectl get all
서비스 삭제하기
- kubectl delete svc -all
- kubectl delete pod nginx
- 남아있던 nginx-pod도 지워준다.
- 다 지웠으나, 기본 디폴트 Clouster IP는 지울 수 없다.
vi nginx-pod.yml
apiVersion: v1 # api의 버전 kind: Pod # yml로 생성하고사하는것은 pod이다. metadata: # pod 정보 설정 name: nginx-pod # 이름은 nginx-pod labels: # labels app: nginx-pod spec: containers: # 컨테이너의 이름과 이미지 정의, #여러개를 -로 구분하여 정의할 수 잇따. - name: nginx-pod-container image: nginx
문법
- https://kubernetes.io/ko/docs/concepts/workloads/pods/
- 중요한 에러를 발생시키지는 않지만, 공식문서의 문법을 따라해본다.
- Ansible처럼 -에도 간격을 주는것이 아니라, -를 제외한 name부터 간걱을 준다.
pod생성하기
kubectl apply -f nginx-pod.yaml
- docker images를 보면 kube-apiserver, kube-controller-manager, kube-proxy등 docker와 kubernetes는 서로 관련이 많음을 볼 수 있다.
- 방금 생성한 nginx-pod가 잘 러닝중이다.
kubectl get pod -o wide
- kubectl get pod명령어를 조금 더 자세하게 살펴본다.
kubectl describe pod nginx-pod
- describe 명령어는 docker에서 inspect와 비슷하다. nginx-pod에 대한 자세한 정보를 보여준다.
vi clusterip-pod.yaml
apiVersion: v1 kind: Service metadata: name: clusterip-service-pod spec: type: ClusterIP # --type옵션, ClusterIP를 nginx-pod에 연결해준다. selector: app: nginx-pod # 앞서만든 nginx-pod와 이름이 같아야한다. ports: - protocol: TCP port: 80 # hostport를 말한다. targetPort: 80 # 목표 port, 내부에서 들어오는 트래픽을 포트포워딩한다.
- kubectl apply -f clusterip-pod.yaml
- kubectl get svc로 생성된것을 확인한다.
- 내부에서 curl 명령어로 html이 잘 출력된다.
- kubectl describe svc clusterip-service-pod
- clusterip-service-pod 의 상세정보를 살펴본다.
만약 yaml파일을 수정해서 selector입력에 오류를 넣어준다면
apiVersion: v1 kind: Service metadata: name: clusterip-service-pod spec: type: ClusterIP selector: app: nginx-pod1 # 여기에 1을 넣어서 일부러 오타를 넣어준다. ports: - protocol: TCP port: 80 targetPort: 80
- 에러는 나지 않는다.
- 그러나 서비스를 연결하지 못했다.
- kubectl get svc에 결과가 나오지 않는다.
만약 yaml파일에서 호스트포트를 8080으로 바꾸면?
apiVersion: v1 kind: Service metadata: name: clusterip-service-pod spec: type: ClusterIP selector: app: nginx-pod ports: - protocol: TCP port: 8080 # 여기를 80 -> 8080으로 수정했다. targetPort: 80
- kubectl get svc로 확인하니, 8080포트로 바뀌엇다.
- curl에서 8080포트로 적용하니 html이 잘 나온다.
edit 명령어
kubectl edit svc clusterip-service-pod
- 실행중인 서비스를 vi명령어를 쓰듯이 내용을 수정할 수 있다.
- 방금 변경한 8080포트를 80포트로 돌려주고 저장한다.
- 80포트로 다시 돌아왔다.
vi nodeport-pod.yaml
apiVersion: v1 kind: Service metadata: name: nodeport-service-pod spec: type: NodePort selector: app: nginx-pod # 여기서 app아니라 good이든 어떤거든 pod에 정의된 이름과 매핑만되면 된다. ports: - protocol: TCP port: 80 # 호스트 포트 targetPort: 80 # 컨테이너 포트 nodePort: 30080 # 노드포트는 랜덤생성되지만, 30000~32767 정도까지 내 임의로 할당도 가능하다.
- kubectl apply -f nodeport-pod.yaml
- nodeport-pod pod에 nodeport를 연결한다.
- ClusterIP로 curl명령어에서 html 출력된다.
- 마찬가지로 호스트IP:30080포트도 잘 접속된다.
vi loadbalancer-pod.yaml
apiVersion: v1 kind: Service metadata: name: loadbalancer-service-pod spec: type: LoadBalancer # LoadBalancer 유형을 사용한다. externalIPs: # 호스트IP를 입력한다. - 192.168.56.119 selector: app: nginx-pod ports: - protocol: TCP port: 80 targetPort: 80 #컨테이너포트라서 함부러 바꾸면 안된다.
kubectl apply -f loadbalancer-pod.yml
kubectl get svc -o wide
kubectl describe svc loadbalancer-service-pod
- clusterIP로 접속
- HOST IP로 접속 (LoadBalancer에서 정의)
kubectl edit pod nginx-pod
명령어에서 image를 검색해서jo1132/web-site:v2.0
으로 넣어본다.
- 현재 Loadbalancer 서비스가 생성되어 있으니, 호스트IP로 접속이 가능하다.
- 접속해보니 웹페이지가 바뀌었다.