0. NHN 교육 참석 후기
2024.07.08(월) NHN에서 주관하는 K8S 교육을 다녀왔다.
강의실 환경도 쾌적하고 강사님께서 정말 열심히 수업해 주셔서 하루 종일 재미있게 듣고 왔다!
내가 들은 강의는 K8S 기초에 대한 내용으로 CKA를 따기 위해 공부 중이던 나에게 딱 알맞은 강의였다. 혼자 공부 중이던 내용이 정리됐고, 핸즈온이 잘 되어있어 docker, k8s 명령어를 손에 익히기에 좋았다.
강의를 70% 이상 수료하면 이런 귀여운 수료증도 줘서 뿌듯해진다.
https://www.nhncloud.com/kr/edu 에서 신청 가능하니 관심 있는 교육이 있다면 NHN Cloud 가입 후 신청하자~
내가 들은 강의는 3가지 챕터로 이루어져 있다.
- 컨테이너와 도커 이해하기
- 쿠버네티스 개념 및 구조 파악하기
- 쿠버네티스의 주요 리소스 오브젝트 개념 익히기
하단에는 강의 내용을 정리해 놓았으니 내용 정리가 필요한 분들은 참고하시길~
1. 컨테이너와 도커 이해하기
1) 컨테이너 이해하기
컨테이너를 배우며 헷갈리기 쉬운 컨테이너, 컨테이너 이미지, 도커 이 세 가지의 차이에 대해 이해해 본다.
1-1) 컨테이너
컨테이너는 애플리케이션을 실행하는 게 목적이다. 즉, 컨테이너어는 애플리케이션과 애플리케이션이 돌아갈 수 있게 하는 환경(모든 종속성, 라이브러리 등)을 하나의 컨테이너에 넣어 애플리케이션이 돌아가게 포장하는 기술 중 하나이다. 컨테이너 안의 내용물은 다 같아 컨테이너만 실행 가능하면 어디서든 항상 동일한 애플리케이션을 동작하게 해 준다.
ㄱ. 컨테이너 vs VM
컨테이너와 VM의 가장 큰 차이는 컨테이너는 Guest os가 없기에 VM 보다 가볍다는 것이다. 이에 컨테이너는 VM에 비해 실행 시간이 매우 빠르다.
VM은 hypervisor라는 가상화 기술로 하드웨어 레벨의 강력한 독립적인 환경을 제공하는 기술이다.
ㄴ. 컨테이너 특징
- 독립성 : 각자 격리된 환경에서 애플리케이션을 실행할 수 있다.
- 이식성 : 어떤 환경에서 컨테이너를 실행해도 동일한 컨테이너가 실행되며 이식하기 편리하다.
- 가볍고 빠른 배포 : 가볍기에 빠르게 배포 가능 하다.
- 자원관리 : host os의 커널을 공유하기에 자원 관리에 편하다.
- 스케일링 : 컨테이너를 조율해 주는 프로그램을 사용하면 편리하게 자원 관리가 가능하다.
1-2) 컨테이너 이미지
애플리케이션을 실행하기 위한 모든 것을 이미지(하나의 파일)로 저장해 놓은 것이다. 이 이미지를 가져와 언제든지 애플리케이션을 실행할 수 있다.
기존 이미지나(docker hub, private registry(ncr))나 만든 이미지(Dockerfile)를 사용할 수 있다.
CSP에서 제공하는 이미지(ncr의 이미지) 같은 것을 사용하면 보안취약점 분석을 할 수 있고, 이미지 정리 및 보호, 이전 간 이미지 복제가 가능하다는 등의 장점이 있다.
ㄱ. 컨테이너 이미지 특징
여러 레이어를 쌓아서 하나의 이미지로 만들어준다. 레이어는 애플리케이션을 실행하기 위한 구성, 변경 사항을 하나씩 쌓아 만드는 것이다. 레이어들은 순차적으로 쌓이며 상위 레이어가 하위 레이어의 변경 사항을 덮어쓴다. 이미지는 read only여서 불변성이라는 특징을 가지고 있다.
ㄴ. 컨테이너 레이어(layer)
컨테이너 이미지는 여러 레이어로 구성된다. 컨테이너 이미지는 read만 가능하여 편집이 불가하다.
컨테이너 이미지를 컨테이너로 만들면 각 레이어는 순차적으로 쌓이며 상위 레이어가 하위 레이어에 변경 사항을 덮어 씌운다. 이미지 레이어 위에 컨테이너 레이어가 쌓인다. 이 컨테이너 레이어는 read-write로 컨테이너의 모든 변경 사항을 저장하는 것이다. 컨테이너를 삭제하면 컨테이너 레이어도 삭제된다. 실행 중 상태에서 변경이 가능하다.
즉, 컨테이너 이미지는 애플리케이션을 실행하기 위한 모든 구성 요소를 포함하는 읽기 전용 탬플릿(파일)이며 컨테이너는 어플리케이션을 실행하기 위한 모든 구성요소를 포함 한 가변적으로 실행 중인 인스턴스이다.
3) 도커
도커는 컨테이너 기반 오픈 소스 플랫폼이다. 도커를 사용하면 빠르게 도커 이미지를 빌드. 테스트, 배포할 수 있게 해 준다. 환경을 일치시키기 위해서 사용한다.
지금까지 배운 도커, 컨테이너, 컨테이너 이미지는 하단 글을 통해 한번에 이해할 수 있다.
"도커"라고 하는 컨테이너를 실행하는 플랫폼 위에 레지스트리에서 "컨테이너 이미지"를 이용해 "컨테이너"를 실행시켜 애플리케이션을 동작시킨다.
3-1) 도커의 구조 및 역할
도커의 구조는 클라이언트 - 서버 구조이다. Client에서 명령을 실행하고, Docker client의 명령은 Docker Host의 Docker Daemon으로 전달된다. Docker Daemon은 명령을 처리한 뒤 결과를 Client에게 전달해 준다.
ㄱ. pull
Docker 레지스트리에서 빌드된 컨테이너 이미지를 가져온다.
Docket client가 명령을 하면 daemon이 명령을 받아서 registry로 보내 image를 가져온다.
이미지 pull 주소 : docker.io/library/nginx:1.25
- 접두사(prefix) : "docker.id/library/"
컨테이너 이미지의 레지스트리를 가리킨다. 생략되면 도커 허브로 간다.
- 접미사(suffix) : ":1.25"
접미사가 생략되면 lastest 태그를 가지고 온다. 특정 태그를 선택하면 해당 태그로 가져온다.
ㄴ. push
저장소에 이미지를 보내는 작업이다. 이미지를 다운로드하는 pull image와 반대의 작업을 한다고 생각하면 된다.
ㄷ. run
이미지를 사용해 컨테이너를 생성하고 실행하는 명령어이다.
docker run client가 실행시키면 이미지가 있을 경우 데몬에서 이미지를 가져와서 컨테이너를 실행한다.
이미지가 없으면 레지스트리에서 이미지를 가져와 컨테이너를 실행한다.
$ docker run --name [컨테이너 명] -d -p [호스트 포트]:[컨테이너 포트] [이미지]
$ docker run --name webserver -d -p 8080:80 nginx
- 호스트 포트 : 외부에서 호스트 머신에 접근할 때 사용하는 포트이다. 임의로 지정 가능하다.
- 컨테이너 포트 : 컨테이너 내부에서 실행 중인 서비스의 포트이다.
ㄹ. build
Docker 이미지를 생성하는 명령어이다. 명령어 사용 시 명령된 지시어를 순차적으로 실행해(레이어를 쌓아서) 이미지를 구축한다.
3-3) Dockerfile
원하는 이미지를 Dockerfile로 만들고 doker build 명령어를 사용하면 docker image가 만들어진다. run 명령어 사용하면 해당 이미지로 docker 컨테이너가 만들어진다.
이때 작업은 Dockerfile에 적힌 순서로 진행된다.
# Dockerfile 작성
$ vi Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000
# Dockerfile로 이미지 빌드
$ docker build -t todoweb .
# Dockerfiile로 생성된 이미지를 컨테이너로 실행
$ docker run --name todolist -dp 3000:3000 todoweb
- FROM : 베이스 이미지를 어떤 걸 쓸 건지 선택하는 항목이다.
- WORKDIR : 컨테이너가 사용하는 작업 디렉터리를 선택하는 항목이다. 이후 명령들은 이 디렉토리 내에서 실행된다.
- COPY : 로컬 파일을 컨테이너 내부로 복사하는 항목이다. COPY B /A/B 라 한다면 B에 있는 모든 걸 컨테이너의 A로 모두 복사해 주는 것이다. 작업 디렉터리로 설정한 경로는 WORKDIR 항목에서 만들어져서 A 경로가 컨테이너 내부에 생성되어 있다.
- RUN : 컨테이너 올린 뒤 실행 시킬 명령어들을 넣는 항목이다.
- ENV: 환경 변수를 설정하는 항목이다. (ex : ENV PORT 8080 )
- EXPOSE :컨테이너 포트를 지정하는 항목이다.
- CMD : 이미지가 실행될 때 실행될 명령을 지정한다. copy에서 파일을 가져와서 해당 파일의 index.js 파일을 node로 실행시켜 주는 것이다.
- $ docker build -t todoweb . 에서 마지막은 Dockerfile을 찾을 위치로 현위치면 . 을 찍으면 된다.
3-4) Docker 명령어 사용해 보기
ㄱ. Docker 버전 확인
Docker가 정상적으로 설치되었는지 확인하며 Client-Server 구조도 확인 가능하다.
$ docker version
ㄴ. Docker 환경 확인
컨테이너 수, 도커 버전, 스토리지 드라이버 종류, OS 종류 등을 확인할 수 있다.
$ docker system info
ㄷ. 이미지 다운로드하기
docker pull 명령어 사용해 이미지를 다운로드한 뒤 docker images 명령어로 현재 존재하는 이미지 확인이 가능하다.
$ docker pull nginx
$ docker images
ㄹ. 컨테이너 실행
docker run 명령어 사용해 컨테이너를 실행 한 뒤 docker ps로 생성된 컨테이너 리스트를 확인한다.
$ docker run --name webserver -d -p 80:80 nginx
$ docker ps
ㅁ. 컨테이너 접근
docker exec를 사용해 컨테이너 내부의 실행 파일 또는 명령어를 실행할 수 있다. 하단 명령어를 사용해 생성한 컨테이너 내부로 들어가 본다.
$ docker exec -it webserver /bin/bash
ㅂ. 로그 확인
docker logs 명령어를 사용해 컨테이너의 로그를 출력해 확인할 수 있다.
$ docekr logs webserver
3-5) Docker-compose란?
여러 컨테이너를 docker-compose.yml 파일에 기술해 docker compose up이란 명령어를 통해 사용한다. 여러 번 반복해야 할 docker 작업을 단축시켜 줄 수 있다.
다만 오토 스케일링 등 여러 기능이 부족해 kubernetes와 같은 오케스트레이션 툴이 발전했다.
2. 쿠버네티스 개념 및 구조 파악하기
쿠버네티스는 조타수라는 어원에서 시작한 오픈 소스 툴이다.
쿠버네티스는 선언적 구성으로 이루어져 있다. 관리자가 선언해 놓은, 설정해 놓은 값을 유지하려고 계속 모니터링하고 구성한다.
1) 관리형 K8S 장점
쿠버네티스는 자체적 구축해도 되며, CSP의 관리형 K8S를 사용해도 된다.
- CSP의 타 서비스와 연동가능(LB, 오토스케일링) / 별도 필요한 설정이 줄어든다.
- 고가용성을 보장하는 Master node를 CSP에서 관리한다.
- LB를 이용한 서비스 공개가 가능하다.
- 웹 콘솔을 이용한 간단한 구축이 가능하다. (클러스터, 노드 K8S 버전 업그레이드 지원한다. 다만, 예전 버전은 API 주소들이 바뀔 수 있어서 주의해야 한다.)
2) 용어 정리
- Node : K8S의 가장 기본적인 작업 단위로 실질적인 위크로드를 구동하는 역할을 한다.
- Cluster : 여러 node가 모여 구성된 전체 시스템 (Master node(=contrrol plane, control node) + Workwer nodes(=node))
3) 쿠버네티스 구조
3-1) Master node
클러스터의 상태 및 구성을 관리하며 애플리케이션의 배치와 실행을 조정하는 역할을 한다.
- apiserver : master의 모든 명령을 조절해 주는 역할을 한다.
- scheduler : 리소스(컨테이너)들을 실행할 때 어떤 node에 올릴지 판단해 준다.
- controller manager : 객체들을 모니터링하다가 이상이 생기면 정상화시켜 준다.
- cloud controller manager : CSP랑 연결할 때 사용하는 연결 고리이다.
- ETCD : 클러스터 정보가 쌓이는 DB이다.
3-2) Worker node
실제 애플리케이션이 동작하는 노드이다.
- kublet : 모든 노드에 실행되는 구성 성분으로 API와 통신한다.
- kube-proxy : 네트워크 설정을 해주는 역할을 한다.
- runtime : 컨테이너가 돌아갈 수 있는 환경이다. (요즘은 containerD와 같은 것을 사용한다)
3. 쿠버네티스의 주요 리소스 오브젝트 개념 익히기
worker node에 자원을 올리기 위한 개념에 대해 배운다.
k8s와 상호작용하기 위해선 kubectl이 필요하다. kubeconfig를 통해 클러스터 API 서버와 인증된 RESTful api 요청을 주고받아 서버와 통신한다.
1) 명령적 관리와 선언적 관리
1-1) 명령적 관리 (Imperative management)
명령어를 사용해 리소스를 생성, 수정, 삭제를 한다. 신속한 변경이 가능한다.
1-2) 선언적 관리 (Declarative managent)
yaml 파일을 사용해 리소스를 원하는 상태로 정의할 수 있다.
버전 관리를 위해 선언적 관리를 사용하는 것을 권장한다.
kubenetes에서 yaml 파일에는 apiversion, kind, metadata, spec 네 가지는 항상 있어야 하는 설정이다.
apiVersion: v1
kind: Pod
metadata:
name: web-app
labels:
app: web-simple
spec:
containers:
- name: web-server
image: nginx:latest
ports:
- containerPort: 80
2) 자원
2-1) pod
쿠버네티스의 가장 기본적인 배포 단위로 pod 단위로 애플리케이션을 띄운다. pod 안에는 여러 개의 컨테이너가 올라갈 수 있다. pod는 고유한 IP 주소를 가지고 있기에 pod 내부 컨테이너들은 내부 통신(localhost)을 한다.
Pod는 영구한 것이 아니라 일회용이라는 것을 인지하고 다뤄야 한다.
<두 개의 컨테이너가 생성되는 pod yaml 파일 예시>
$ vim pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: 2container-pod
spec:
containers:
- name: web-server
image: nginx:latest
ports:
- containerPort: 80
- name: database
image: mysql:latest
env:
- name: MYSQL_ROOT_PASSWORD
value: mysecretpassword
- labels : app = web-simple이라는 명찰을 달아주는 것이다.
- env :으로 환경 변수를 맞춰 줄 수 있다. mysql root password를 미리 설정해 놨다.
Kubernetes 클러스터에 리소스를 배포 또는 업데이트하는 apply 명령어로 pod를 배포한다.
$ kubectl apply -f <파일 또는 디렉토리 경로>
pod의 상태를 확인한다.
$ kubectl get pods -o wide
$ kubectl get pods --show-labels
-o wide / --output wide 옵션을 사용하면 기본 출력 정보에 "파드가 실행 중인 노드 이름", "IP 주소", 사용 중인 컨테이너 이미지 등의 자세한 정보를 볼 수 있다. --show-labels 옵션으로 설정한 라벨을 볼 수 있다.
pod의 상세 정보를 출력한다.
$ kubectl describe pod 2container-pod
pod의 이벤트와 상태, 환경 변수, 포트, 리소스 요청 같은 정보를 확인 가능 하다. pod 생성간 에러가 나면 에러 로그도 볼 수 있다. describe pods 뒤에 탭 하면 자동 완성 되게 하는 기능이 있다. (윈도우 등 설치해서 사용하면 좋다)
실행 중인 K8S 파드의 컨테이너에서 특정 명령을 실행하거나 컨테이너 쉘에 접속 가능하다.
$ kubectl exec -it <파드 이름> -c <컨테이너 이름> -- <명령어>
$ kubectl exec -it 2container-pod -c database -- /bin/bash
2-2) replicaset
pod를 복제를 관리하고 유지하는 자원이다. pod의 상위 레벨로 pod의 개수를 자동으로 확장하거나 축소하기에 pod는 일회성 자원이다.
<replicaset yaml 파일 예시>
$ vim replicaset.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx-replicaset
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:latest
pod의 labels를 기반으로 모니터링한다. template 밑의 부분이 pod의 정보이다. 이에 pod의 labels와 RS의 labels는 같아야 한다.
rs를 생성한다.
$ kubectl apply –f replicaset.yaml
생성된 rs와 pod를 확인한다.
$ kubectl get rs,pods
$ kubectl get pods -o wide --show-labels
$ kubectl get pods –w
-w 옵션으로 pod가 실시간 변하는 것을 확인할 수 있다.
rs를 삭제한다.
$ kubectl delete replicaset nginx-replicaset
2-3) Deployment
ReplicaSet을 기반으로 하며 애플리케이션의 배포와 비슷한 롤백(이전 버전으로 복구), 롤아웃(배포)의 역할을 하는 자원이다.
- 롤링 업데이트
- 롤백
- 선언적 구성
- 자동 스케일링
<Deployment yaml 파일 예시>
replicaset과 kind만 다르다.
$ vim deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:latest
Deployment를 배포한 뒤, 상세 정보를 확인한다.
$ kubectl apply –f deployment.yaml
$ kubectl describe deployment nginx-deployment
yaml 파일 설정을 변경 후 다시 apply를 한 뒤, 롤백 히스토리를 확인한다.
$ kubectl rollout history deployment <dploy name>
$ kubectl rollout history deployment <dploy name> --revision=2
--revision=2 옵션으로 상세 확인 가능하다.
최근 업데이트를 되돌리는 명령어로 이전 상태로 롤백한다.
$ kubectl rollout undo deployment <depoyment 이름>
! 이때 k8s는 클러스터 내부 어떤 설정 없이 다른 node위의 모든 pod끼리 서로 통신되는 특징이 있다.
2-4) service
애플리케이션 컨테이너에 대한 네트워크 접근성을 관리하고 노출하는 자원이다. 클러스터 내의 다른 컨테이너, 외부 요청자들이 특정 애플리케이션을 찾을 수 있게 해주는 역할을 한다.
Yaml 파일의 Selector 항목을 사용해 운영 중인 pod들을 선택하여 트래픽을 라우팅 하거나 클러스터 외부나 내부 다른 파드로 포트를 라우팅 할 수 있다.
service는 4가지 서브 유형을 제공한다. (clusterIP NodePort, LoadBalancer, Externalname)
Tip! 서비스는 보통 성공적으로 올라오나 labels에서 문제가 생기는 경우가 있다. 이에 selector가 어떤 labels를 보고 라우팅 하는지 확인하는 게 좋다.
ㄱ. clusterIP
내부 리소스를 묶어서 서비스를 안전하게 검색하고 사용할 수 있게 해 준다. 접근하는 단일 지점을 생성한다.
<clusterIP yaml 파일 예시>
$ vim clusterip.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 8080
targetPort: 80
type: ClusterIP
apply 명령어로 clusterIP를 생성 한 뒤, get 명령어로 확인한다.
$ kubectl apply -f clusterip.yaml
$ kubectl get service -o wide
$ kubectl get all -o wide
all로 주요 리소스들을 한 번에 조회할 수 있다.
ClusterIP로 정상적으로 서비스에 접근되는지 보기 위해서는 워커 노드에 접속하여 확인 가능하다.
$ ssh -i [키파일] ubuntu@[워크노드IP]
혹은 kubectl exec 명령어로 pod에 접근해 curl 명령어로 통신 확인이 가능하다.
ㄴ. NodePort
클러스터의 모든 node에서 특정 port를 여는 것으로 30000~32767 사이의 port 사용 가능하다. 외부에서 서비스 접근 가능하게 하는 포트이다. NodePort로 들어오는 트래픽을 내부 서비스 (일반적으로 ClusterIP 서비스)로 라우팅 한다.
<NodePort yaml 파일 예시>
$ vim nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport-service
spec:
selector:
app: web-simple-ncr
ports:
- protocol: TCP
port: 80
targetPort: 3000
nodePort: 31000
type: NodePort
apply 명령어로 nodeport를 생성 한 뒤, get 명령어로 확인한다.
$ kubectl apply -f nodeport.yaml
$ kubectl get service -o wide
pod 상세 정보 확인하여 Labels가 nodeport의 selector와 동일한지 확인한다.
$ kubectl describe pod [pod 명]
ㄷ. LoadBalancer
일반적으로 CSP에서는 CSP에서 제공하는 LB가 자동으로 통합된다. LB는 인스턴스 레벨을 묶으니 pod를 엮는 게 아닌 node를 엮어주는 것이다. LB를 만들면 Nodeport와 cluster IP가 다 있어야 한다. 이에 nodeport, clusterIP를 알아서 만든다. LB의 port랑 clusterIP의 port는 동일하게 설정된다.
<LoadBalancer yaml 파일 예시>
$ vim lb.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-loadbalancer-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 1234
targetPort: 80
type: LoadBalancer
apply 명령어로 loadbalancer를 생성 한 뒤, get 명령어로 확인한다.
$ kubectl apply -f lb.yaml
$ kubectl get service -o wide
$ kubectl get all -o wide
모든 자원을 조회하여 LoadBalancer의 selector가 어떤 자원을 가리키고 있는지 확인한다.
2-5) namespace
클러스터 내의 자원을 논리적으로 격리한다. 리소스를 격리하고, 그룹화하며 액세스 제어 및 권한 관리, 리소스 이름 충돌을 방지한다.
명령어나 yaml 파일을 사용해 namespace를 생성한다.
$ kubectl create namespace [네임스페이스 이름]
$ vim ns-product.yaml
apiVersion: v1
kind: Namespace
metadata:
name: product
$ kubectl apply -f ns-product.yaml
<namespace 지정한 pod yaml 파일 예시>
apiVersion: v1
kind: Pod
metadata:
name: dev-pod
namespace: dev
spec:
containers:
- name: nginx
image: nginx:latest
namespace가 정상적으로 생성 됐는지 확인한다
$ kubectl get ns
$ kubectl get pods -n dev
$ kubectl get pods -A
-n dev 옵션으로 네임스페이스 지정해서 확인 가능 하다.
-A 옵션으로 모든 네임스페이스의 pod를 볼 수 도 있다.
! 같은 네이스페이스에 있는 자원끼리만 통신이 가능하다.
'IT 강의 > 도커 쿠버' 카테고리의 다른 글
[CKA 강의 요약] Practice Test - Deployments, Solution - Deployments (Optional) (0) | 2024.07.02 |
---|---|
[CKA 강의 요약] Namespaces (2) | 2024.06.27 |
[CKA 강의 요약] Practice Test - Services (0) | 2024.06.27 |
[CKA 강의 요약] Services - Loadbalancer (0) | 2024.06.25 |
[CKA 강의 요약] Services Cluster IP (0) | 2024.06.20 |