🏫 Cloud Practice/🧪 Docker, K8s, IaC

쿠버네티스의 Deployment, Namespace, Service에 대해 알아보자

나리 집사 2023. 11. 21. 11:47

이론

Deployment

배포를 위한 오브젝트

Namespace

격리된 환경을 제공하는 오브젝트

Service

오브젝트들을 외부에 "서비스"하기 위한 오브젝트 = public

nodePort: 실제 서버외부에 노출되는 노드들의 포트이다. 30000~32765 까지의 포트가 사용 가능하다.

port: (서비스) 포트를 말한다. 서비스는 작은 로드밸런서라고 생각하면 좋다. IP와 port가 존재한다.

targetPort: pod의 포트이다.

 

실습

# <명령어 자동완성>

$ apt-get install bash-completion  
$ echo 'source <(kubectl completion bash)' >>~/.bashrc
$ echo 'source <(kubeadm completion bash)' >>~/.bashrc
 
$ kubectl completion bash >/etc/bash_completion.d/kubectl

# kubectl 대신 k만 쳐도 되게끔 kubectl을 k로 간소화
$ ln -s /usr/bin/kubectl /usr/local/bin/k

Deployment

Pod

다음과 같이 pod를 띄워볼 수 있다.

$ vi test.yml
apiVersion: v1
kind: Pod
metadata:
  name: http-t1
  labels:
    app: nginx
spec:
  containers:
  - name: nginx-container
    image: http:latest
    ports:
    - containerPort: 80

$ kubectl apply -f test.yml


replicaset

replicaset은 pod를 몇 개 띄울지에 대한 것이다. 즉, pod를 복제하는 것에 대한 것이다.

replicaset을 통해 항상성(고가용성)을 확보할 수 있고, 버전관리에 반드시 필요하다.

"selector"를 통해 복제할 pod의 라벨을 선택한다.

$ vi nginx-rep.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myrs
spec:
  replicas: 3
  selector:
    matchLabels:
      dev: my-label
  template:
    metadata:
      name: mypod
      labels:
        dev: my-label
    spec:
      containers:
      - name: mycon
        image: nginx:latest
        ports:
        - containerPort: 80
 
$ kubectl apply -f nginx-rep.yml

# 정보확인.

# --watch : 실시간 모니터링

배포

1) “hello k8s”라는 index.html 파일을 httpd:latest 컨테이너를 베이스로 하여 k8s 로컬 클러스터에 배포하고 싶다. 

  1. 인덱스 파일 생성 및 Dockerfile 작성
  2. 도커 이미지 빌드
  3. 매니페스트 파일 작성 => apply
$ echo "hello k8s" > index.html
$ vi Dockerfile
FROM httpd:latest
ADD ./index.html /usr/local/apache2/htdocs/index.html

# 도커 설치
$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh

# 빌드
$ docker build -t dahyeonn/myhttpd:1.0 .

# 로그인
$ docker login
# 도커 허브 push
$ docker push dahyeonn/myttpd:1.0

$ vi pod.yml
apiVersion: v1
kind: Pod
metadata:
  name: myhttp
  labels:
    app: myhttp
spec:
  containers:
  - name: myhttp-con
    image: dahyeonn/myhttpd:1.0
    ports:
    - containerPort: 80

$ kubectl apply -f pod.yml

2) replicaset을 3개로 하여 매니페스트 파일을 작성하고, 이미지는 도커 허브에 업로드 해서 구성해본다.

$ vi rep.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: mytthp-rep
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-http
  template:
    metadata:
      name: mypod
      labels:
        app: my-http
    spec:
      containers:
      - name: mycon
        image: dahyeonn/myhttpd:latest
        ports:
        - containerPort: 80

$ kubectl apply -f rep.ym

 

3) 동일한 이미지를 사설저장소에 push하고 로컬 클러스터에 배포해본다.

# 사설 저장소 ip 예시: 125.178.222.208:5000

# 우리 클러스터의 CRI인 containerd의 설정 파일
$ vi /etc/containered/config.toml

# docker에서 /etc/docker/daemon.json 파일에서 사설저장소를 insecure 처리했던것처럼, 
# containerd도 비슷한 설정을 해줘야 한다.

$ vi ip-rep.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: ip-rep
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ip-http
  template:
    metadata:
      labels:
        app: ip-http
    spec:
      containers:
      - name: myip
        image: 125.178.222.208:5000/ipnginx:latest
        ports:
        - containerPort: 80

$ kubectl apply -f ip-rep.yml

$ kubectl get pod -o wide
# 이렇게 진행하면, 이미지를 못받아온다. (ImagePullBackOff)

# pod 이름으로 검색
$ kubectl describe pod ip-rep-czqf8
# 자세한 에러 확인
# containerd server gave HTTP response to HTTPS client
# 구글링을 해서 에러를 해결한다.

$ vi /etc/containerd/config.toml
# 아래의 내용을 추가한다.
# 3개의 노드에 전부 아래의 내용을 추가한다.
# 왜냐하면 실질적으로 image을 pulling 해와서 pod를 띄우는건 worker노드들이기 때문이다.

[plugins."io.containerd.grpc.v1.cri".registry.mirrors."125.178.222.208:5000"]
   endpoint = ["http://125.178.222.208:5000"]
[plugins."io.containerd.grpc.v1.cri".registry.configs."125.178.222.208:5000".tls]
   insecure_skip_verify = true

# 해당 주소를 갖는(125.178.222.208:5000 의 사설저장소를 tls 인증서 없이(=https를 안하겠다) http로 사용하겠다.

$ kubectl get pod
NAME               READY   STATUS    RESTARTS   AGE
http-t1            1/1     Running   0          19h
ip-rep-8gz5q       1/1     Running   0          18s
ip-rep-s6nqk       1/1     Running   0          18s
ip-rep-v8k5q       1/1     Running   0          18s

# 결론적으로 아래 명령어만 각 노드에 복붙하면 된다. 
# 위에서 toml 파일 수정했으면 지우고 하거나 하지 않으면 된다.
export REG_ENDPOINT=125.178.222.208:5000

cat << EOF >> /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."${REG_ENDPOINT}"]
      endpoint = ["http://${REG_ENDPOINT}"]
[plugins."io.containerd.grpc.v1.cri".registry.configs."${REG_ENDPOINT}".tls]
      insecure_skip_verify = true
EOF

systemctl restart containerd

# 모든 파드를 삭제한다. 위험하지만, 실습으로 해본다.
$ kubectl delete pod --all --all-namespaces

 

4) deployment를 이용한 실습

$ vi ip-dep.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx-dep
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-nginx
  template:
    metadata:
      name: my-nginx-pod
      labels:
        app: my-nginx
    spec:
      containers:
      - name: nginx
        image: 125.178.222.208:5000/ipnginx:latest
        ports:
        - containerPort: 80

 

 

Namespace

개념

# namespace 생성
$ vi myns.yml
apiVersion: v1
kind: Namespace
metadata:
  name: myns
$ kubectl apply -f myns.yml
$ kubectl get ns

# 매니페스트 파일 상에서 ns 지정
$ vi nginx-pod.yml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  namespace: myns
  labels:
    app: nginx
spec:
  containers:
  - name: nginx-container
    image: nginx:test
    ports:
    - containerPort: 80
    ...
 
# 삭제
$ kubectl delete ns myns
namespace "myns" deleted
 
# namespace를 삭제하면 그 안에 있는 오브젝트들도 날라간다.
$ kubectl get pod --all-namespces | grep myns

배포

1) 하나의 매니페스트 파일(lunch-dep.yml)을 통해 lunch라는 namespace에 httpd:latest를 이미지로 하는 deployment를 만든다. 이때, deployment의 replicaset은 3개이다. kubectl apply -f lunch-dep.yml 명령어만 사용한다.

$ vi lunch-dep.yml
apiVersion: v1
kind: Namespace
metadata:
  name: lunch
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: lunch-dep
  namespace: lunch
spec:
  replicas: 3
  selector:
    matchLabels:
      app: food
  template:
    metadata:
      labels:
        app: food
    spec:
      containers:
      - name: httpd-con
        image: httpd:latest
        ports:
        - containerPort: 80
 
# 적용
$ kubectl apply -f lunch-dep.yml

# namespace의 pod 확인
$ kubectl get pod -n lunch

2) httpd:latest라는 이미지를 Pod로 하는 Deployment를 만들고 싶다. 레플리카는 3개로 하고 Pod의 라벨은 app: httpd로 해서 생성한다. 이때, web: httpd로 하면 안되고 app: httpd로 한다.

$ vi web-dep.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-httpd-dep
spec:
  replicas: 3
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      name: my-httpd-pod
      labels:
        app: httpd
    spec:
      containers:
      - name: httpd-container
        image: httpd:latest
        ports:
        - containerPort: 80

 

Service

개념

# 위에서 생성한 web-dep.yml이 적용된 상태여야 한다.

$ vi web-svc.yml
apiVersion: v1
kind: Service
metadata:
  name: web-svc
spec:
  type: NodePort
  selector: 
    app: httpd
  ports:
  - nodePort: 31000
    port: 80
    targetPort: 80

$ kubectl apply -f web-svc.yml

# ip:NodePort에서 web이 배포된 것을 확인할 수 있다.

역할

Service는 Loadbalancer 역할을 한다. 이를 확인해보자.

$ vi web-dep.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-httpd-dep
spec:
  replicas: 3
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      name: my-httpd-pod
      labels:
        app: httpd
    spec:
      containers:
      - name: httpd-container
        image: 125.178.222.208:5000/ipnginx:latest # 수정!!
        ports:
        - containerPort: 80

로드밸런싱이 되는 것을 확인할 수 있다.

배포

hello world라는 index.html 파일을 포함하는 myhttpd라는 앱을 하나의 매니페스트 파일을 작성하여 배포해보자.

서비스이름: svc-httpd

서비스포트: 80

타겟포트: 80

노드포트: 32000

라벨 app: myhttpd

$ echo hello world > index.html

$ vi Dockerfile
FROM httpd:latest
ADD ./index.html /usr/local/apache2/htdocs/index.html

$ cat myhttpd.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myhttpd
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myhttpd
  template:
    metadata:
      labels:
        app: myhttpd
    spec:
      containers:
      - name: myhttpd
        image: dahyeonn/myhttpd:1.1
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: svc-myhttpd
spec:
  type: NodePort
  selector:
    app: myhttpd
  ports:
  - nodePort: 32000
    port: 80
    targetPort: 80
    
 $ docker push dahyeonn/myhttpd:1.1

제대로 동작하는 것을 확인할 수 있다.