Dev./Kubernetes & Helm

Kubernetes: 서비스, 파드의 관리자

Ivan'show 2023. 9. 16.
728x90
반응형

서비스 생성

서비스는 파드 집합에 대한 안정적인 접근을 가능하게 하는 추상화 계층이다. (실행중인 애플리케이션 → 서비스로 노출 feat. selector)

서비스는 동일한 기능을 수행하는 파드들에게 단일 IP 주소와 DNS 이름을 제공하며 로드 밸런싱과 트래픽 라우팅을 관리한다. 그렇기 때문에 클러스터 목표 상태(desired state)와 일치하도록 생성되고 삭제되는 과정에서 동적으로 관리해줄 수 있게 된다.

새로운 디렉토리에 rs yaml 파일 생성

# ㅣion-rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: lion
  labels:
    app: lion

spec:
  replicas: 3
  selector:
    matchLabels:
      app: lion
  template:
    metadata:
      labels:
        app: lion
    spec:
      containers:
      - name: lion
        image: teacherssamko/simple-web:v3
        ports:
          - containerPort: 8000
        livenessProbe:
          httpGet:
            path: /
            port: 8000
k create -f lion-rs.yaml
# result
kimminhyeok@Ivans-Mac 0904 % k get po
NAME         READY   STATUS    RESTARTS      AGE
lion-4j644   1/1     Running   1 (31s ago)   2m22s
lion-79bj6   1/1     Running   1 (31s ago)   2m22s
lion-kpzvs   1/1     Running   1 (31s ago)   2m22s

kimminhyeok@Ivans-Mac 0904 % k get rs
NAME   DESIRED   CURRENT   READY   AGE
lion   3         3         3       2m26s

create svc yaml

# lion-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: lion
spec:
  selector:
    app: lion
  ports: # TCP 로 80 포트로 받아서 8000 으로 보내주겠다.
    - protocol: TCP
      port: 80
      targetPort: 8000

selector.app 에 설정되어 있는 lion 이라는 레이블을 가진 파드들에게 서비스를 넘겨주는 구조이다.

k create -f lion-svc.yaml
k get svc

# result
kimminhyeok@Ivans-Mac 0904 % k get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   2d21h
lion         ClusterIP   10.102.129.95   <none>        80/TCP    4s

여기서 클러스터 아이디는 안쪽에서 열린 주소 이기 때문에 로컬에서 바로 접속이 불가능 하다.

# 로컬에서 접속시도 후 실패
kimminhyeok@Ivans-Mac 0904 % curl <http://10.102.129.95>
curl: (28) Failed to connect to 10.102.129.95 port 80 after 75008 ms: Couldn't connect to server

그래서 파드 하나를 골라서 실행을 시키면,

k exec lion-4j644 -- curl <http://10.102.129.95>

# or execute service
k exec lion-4j644 -- curl -s <http://10.102.129.95>

# result
kimminhyeok@Ivans-Mac 0904 % k exec lion-4j644 -- curl <http://10.102.129.95> 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    17    0    17    0     0   1637      0 --:--:-- --:--:-- --:--:--  2428
Too many requests%                                                                                                                           

kimminhyeok@Ivans-Mac 0904 % k exec lion-4j644 -- curl -s <http://10.102.129.95>
Host Name: lion-4j644 / v=2 / Request: 1 /

클러스터 IP 가 클러스터 내부에서만 접근이 가능한 주소인 것을 확인 할 수 있다.


Issue: CrashLoopBackOff

kimminhyeok@Ivans-Mac 0904 % k get po
NAME         READY   STATUS             RESTARTS      AGE
lion-4j644   0/1     CrashLoopBackOff   6 (87s ago)   14m
lion-79bj6   0/1     CrashLoopBackOff   6 (77s ago)   14m
lion-kpzvs   0/1     CrashLoopBackOff   6 (77s ago)   14m

CrashLoopBackOff

파드의 컨테이너가 반복적으로 실패하고 재시작되고 있음을 보여준다.

가능성 있는 원인들

  • 애플리케이션 코드 오류
  • 리소스 제한
  • 설정 오류
  • 종속성 문제

Solution: CrashLoopBackOff

해결방안으로, rs 를 삭제하지 않고 파드들만 삭제하여 rs 가 다시 되살릴 수 있게 한다.

k delete -l app=lion
kimminhyeok@Ivans-Mac 0904 % k delete po -l app=lion
pod "lion-4j644" deleted
pod "lion-79bj6" deleted
pod "lion-kpzvs" deleted

kimminhyeok@Ivans-Mac 0904 % k get po               
NAME         READY   STATUS    RESTARTS     AGE
lion-5qz46   1/1     Running   1 (4s ago)   114s
lion-tc6k2   1/1     Running   1 (4s ago)   114s
lion-zj7w6   1/1     Running   1 (4

컨테이너가 죽는 현상을 막기 위해 이미지를 업데이트헀다.

v3 → v4

이후 다시 rs 를 실행시키고 같은 방법으로 요청을 넣어본다.

# 서비스 실행 후 확인
kimminhyeok@Ivans-Mac 0904 % k get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   2d21h
lion         ClusterIP   10.102.129.95   <none>        80/TCP    21m
# 하나의 파드로 직접 들어와서 요청을 보냈지만, 서비스의 IP 주소, 클러스터 주소로
# 요청을 보내고 있어서 랜덤 파드에서 응답이 돌아오고 있다.

kimminhyeok@Ivans-Mac 0904 % k exec -it lion-hccsb -- sh
/app # curl <http://10.102.129.95>
Host Name: lion-ljn8v / v=4 / Request: 40 /
/app # curl <http://10.102.129.95>
Host Name: lion-j5hfb / v=4 / Request: 40 /
/app # curl <http://10.102.129.95>
Host Name: lion-j5hfb / v=4 / Request: 41 /
/app # curl <http://10.102.129.95>
Host Name: lion-hccsb / v=4 / Request: 41 /
/app # curl <http://10.102.129.95>
Host Name: lion-hccsb / v=4 / Request: 42 /
/app # curl <http://10.102.129.95>
Host Name: lion-hccsb / v=4 / Request: 43 /
/app # curl <http://10.102.129.95>
Host Name: lion-hccsb / v=4 / Request: 45 /
/app # curl <http://10.102.129.95>
Host Name: lion-j5hfb / v=4 / Request: 43 /
/app #

요청을 일관적으로 하나의 파드에서 전달받고 싶으면

# wide search
kimminhyeok@Ivans-Mac 0904 % k get po -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP             NODE       NOMINATED NODE   READINESS GATES
lion-hccsb   1/1     Running   0          5m    10.244.0.192   minikube   <none>           <none>
lion-j5hfb   1/1     Running   0          5m    10.244.0.191   minikube   <none>           <none>
lion-ljn8v   1/1     Running   0          5m    10.244.0.193   minikube   <none>           <none>

curl 을 해당 파드의 IP 로 직접 보내주면 된다.

요청을 하나의 파드로 잡아 줄 수 도 있는데, 서비스에서 요청을 보낼 때 지정한 파드의 주소로 매핑하게 해주면 된다.

k edit svc lion

# sessionAffinity: None -> ClientIP
# svc yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: "2023-09-04T01:25:21Z"
  name: lion
  namespace: default
  resourceVersion: "86392"
  uid: c89b1ee4-caab-40cd-b0c3-47904d9cf79a
spec:
  clusterIP: 10.102.129.95
  clusterIPs:
  - 10.102.129.95
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8000
  selector:
    app: lion
  sessionAffinity: ClientIP
kimminhyeok@Ivans-Mac 0904 % k get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   2d22h
lion         ClusterIP   10.102.129.95   <none>        80/TCP    42m
kimminhyeok@Ivans-Mac 0904 % k exec lion-hccsb -- curl -s <http://10.102.129.95>
Host Name: lion-j5hfb / v=4 / Request: 472 /
kimminhyeok@Ivans-Mac 0904 % k exec lion-hccsb -- curl -s <http://10.102.129.95>
Host Name: lion-j5hfb / v=4 / Request: 473 /
kimminhyeok@Ivans-Mac 0904 % k exec lion-hccsb -- curl -s <http://10.102.129.95>
Host Name: lion-j5hfb / v=4 / Request: 474 /

포트를 이름으로 지정해서 서비스 하기

# lion-rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: lion
  labels:
    app: lion
spec:
  replicas: 3
  selector:
    matchLabels:
      app: lion
  template:
    metadata:
      labels:
        app: lion
    spec:
      containers:
      - name: lion
        image: teacherssamko/simple-web:v4
        ports:
          - containerPort: 8000
            name: http
        livenessProbe:
          httpGet:
            path: /
            port: 8000
          initialDelaySeconds: 3
          periodSeconds: 3
# lion-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: lion
spec:
  selector:
    app: lion
  ports: # TCP 로 80 포트로 받아서 8000 으로 보내주겠다.
    - protocol: TCP
      port: 80
      targetPort: http
      name: http
k create -f lion-rs.yaml

k create -f lion-svc.yaml
kimminhyeok@Ivans-Mac 0904 % k get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   2d22h
lion         ClusterIP   10.103.220.139   <none>        80/TCP    4s
kimminhyeok@Ivans-Mac 0904 % 
kimminhyeok@Ivans-Mac 0904 % k exec lion-r9dbs -- curl -s <http://10.103.220.139>
Host Name: lion-r9dbs / v=4 / Request: 75 /

따로 포트번호를 지정하지 않고 이름만으로도 연결 지을 수 있는 것을 확인

지금은 rs 를 먼저 생성하고 svc 를 생성하면서 연결 시켰기 때문에 파드에는 서비스 정보값이 안들어가 있다. 기존에 있는 파드를 레이블로 삭제하여 재생성 되게 하면 환경 변수값이 저장된다.

# previous

kimminhyeok@Ivans-Mac 0904 % k exec lion-r9dbs -- env
HOME=/root
PYTHON_GET_PIP_SHA256=
PYTHON_GET_PIP_URL=https:
PYTHON_SETUPTOOLS_VERSION=
PYTHON_PIP_VERSION=2
PYTHON_VERSION=3
LANG=C.UTF-
KUBERNETES_PORT_443_TCP_PROTO=t
KUBERNETES_PORT_443_TCP=t
KUBERNETES_PORT=t
KUBERNETES_SERVICE_PORT_HTTPS=
KUBERNETES_SERVICE_PORT=
KUBERNETES_SERVICE_HOST=
KUBERNETES_PORT_443_TCP_ADDR=
KUBERNETES_PORT_443_TCP_PORT=
HOSTNAME=lion-r9dbs

삭제후 재 검색

kimminhyeok@Ivans-Mac 0904 % k delete po -l app=lion
pod "lion-r9dbs" deleted
pod "lion-vhdgt" deleted
pod "lion-xqvkt" deleted

kimminhyeok@Ivans-Mac 0904 % k get po
NAME         READY   STATUS    RESTARTS   AGE
lion-27zpp   1/1     Running   0          33s
lion-m5qq5   1/1     Running   0          33s
lion-qg4fm   1/1     Running   0          33s

kimminhyeok@Ivans-Mac 0904 % k exec lion-27zpp -- env
HOME=/root
PYTHON_GET_PIP_SHA256=
PYTHON_GET_PIP_URL=
PYTHON_SETUPTOOLS_VERSION=
PYTHON_PIP_VERSION=
PYTHON_VERSION=
LANG=C.UTF-
KUBERNETES_PORT_443_TCP=
KUBERNETES_SERVICE_PORT_HTTPS=
KUBERNETES_SERVICE_PORT=
LION_PORT_80_TCP_PROTO=
LION_PORT=tcp://10.103.220.139:80
LION_SERVICE_PORT_HTTP=80
KUBERNETES_PORT_443_TCP_PROTO=t
KUBERNETES_PORT=
KUBERNETES_SERVICE_HOST=
LION_PORT_80_TCP=tcp://10.103.220.139:80
LION_SERVICE_HOST=10.103.220.139
KUBERNETES_PORT_443_TCP_ADDR=
KUBERNETES_PORT_443_TCP_PORT=
LION_PORT_80_TCP_ADDR=10.103.220.139
LION_PORT_80_TCP_PORT=80
LION_SERVICE_PORT=80
HOSTNAME=lion-27zpp

kimminhyeok@Ivans-Mac 0904 % k get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   2d22h
lion         ClusterIP   10.103.220.139   <none>        80/TCP    8m50s

DNS 를 이용해서 조회하기

kimminhyeok@Ivans-Mac 0904 % k exec -it lion-m5qq5 -- sh
/app # curl <http://lion.default.svc.cluster.local>
Host Name: lion-27zpp / v=4 / Request: 124 /
/app # 
/app # curl 
Host Name: lion-qg4fm / v=4 / Request: 133 /

Node port

노드포트는 쿠버네티스에서 외부 트래픽을 클러스터 내부의 특정 서비스로 라우팅 하는 방법중 하나이다.

노드포트는 클러스터 내 모든 노드의 특정 포트에 트래픽을 노출시키고 이를 적절한 파드로 포워딩 한다.

apiVersion: v1
kind: Service
metadata:
  name: lion-nodeport
spec:
  type: NodePort
  selector:
    app: lion
  ports:
      # 기본적으로 그리고 편의상 `targetPort` 는 `port` 필드와 동일한 값으로 설정된다.
    - port: 80
      targetPort: http

Ingress

쿠바네티스 클러스트 내의 서비스에 외부 HTTP/HTTPS 트래픽을 라우팅하는 API 오브젝트이다. 고급 라우팅, SSL 종료 및 도메인 기반 라우팅을 지원한다.

<https://kubernetes.io/ko/docs/concepts/services-networking/ingress/>
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: lion
  # annotations:
  #   nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  # ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: lion-nodeport
            port:
              number: 80
    host: lion.example.com # dns

ReadinessProbe

Health check 처럼 간단한 명령어로 상태확인 가능

# lion-rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: lion
  labels:
    app: lion
spec:
  replicas: 3
  selector:
    matchLabels:
      app: lion
  template:
    metadata:
      labels:
        app: lion
    spec:
      containers:
      - name: lion
        image: teacherssamko/simple-web:v1
        ports:
          - containerPort: 8000
            name: http
        livenessProbe:
          httpGet:
            path: /
            port: 8000
          initialDelaySeconds: 3
          periodSeconds: 3
        readinessProbe:
          exec:
            command:
            - ls
            - /var/ready

컨테이너 내부 안쪽에서 해당 명령어가 실행되고 안쪽에 ready 정보가 없어서 실제로 READY 상태가 되지 않은 것을 확인 가능하다.

svc 내에서도 endpoint 가 이어져 있지 않은 것을 확인가능

k get p

# 
kimminhyeok@Ivans-Mac fourtune % k get po                    
NAME            READY   STATUS    RESTARTS   AGE
fortune         2/2     Running   0          98m
lion-fvrw8      0/1     Running   0          160m
lion-qlr4h      0/1     Running   0          160m
lion-v2-j4njd   1/1     Running   0          3h24m
lion-v2-jmgv4   1/1     Running   0          3h24m
lion-v2-nf44r   1/1     Running   0          3h24m
lion-zh79z      0/1     Running   0          160m
k describe svc lion-nodeport

#
Name:                     lion-nodeport
Namespace:                default
Labels:                   <none>
Annotations:              <none>
Selector:                 app=lion
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.97.6.65
IPs:                      10.97.6.65
Port:                     <unset>  11180/TCP
TargetPort:               http/TCP
NodePort:                 <unset>  30003/TCP
Endpoints:                
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

도커 명령어로 내부에 직접 정보값을 생상하게 되면,

k exec lion-fvrw8 -- touch /var/ready

k exec lion-qlr4h -- touch /var/ready
kimminhyeok@Ivans-Mac fourtune % k get po                    
NAME            READY   STATUS    RESTARTS   AGE
fortune         2/2     Running   0          109m
lion-fvrw8      1/1     Running   0          171m
lion-qlr4h      1/1     Running   0          171m
lion-v2-j4njd   1/1     Running   0          3h35m
lion-v2-jmgv4   1/1     Running   0          3h35m
lion-v2-nf44r   1/1     Running   0          3h35m
lion-zh79z      0/1     Running   0          171m
kimminhyeok@Ivans-Mac fourtune % k describe svc lion-nodeport
Name:                     lion-nodeport
Namespace:                default
Labels:                   <none>
Annotations:              <none>
Selector:                 app=lion
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.97.6.65
IPs:                      10.97.6.65
Port:                     <unset>  11180/TCP
TargetPort:               http/TCP
NodePort:                 <unset>  30003/TCP
Endpoints:                10.244.0.215:8000,10.244.0.217:8000
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

Volume

emptyDir 볼륨으로 일시적인 데이터를 저장하여 파드가 생성될 때 생성되고 파드가 삭제될 때 제거되는 형태로 사용하면서 사용법에 대해 익혀본다.

간단하게 문구를 출력하는 프로그램을 도커파일로 만들어 이미지로 허브에 올려 볼륨 매핑으로 정보를 출력한다.

리눅스환경에서 제공하는 fortune library

# fortuneloop.sh

#!/bin/bash

mkdir -p /var/www
while true
do
    echo $(date) Wrting fortune to /var/www/index.html
    /usr/games/fortune > /var/www/index.html
    sleep 10
done
# Dockerfile
FROM ubuntu:latest

RUN apt-get update && apt-get -y install fortune
ADD fortuneloop.sh /bin/fortuneloop.sh
RUN chmod +x /bin/fortuneloop.sh

ENTRYPOINT ["/bin/fortuneloop.sh"]
# fortune-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: fortune
spec:
  containers:
  - name: html-generator
    image: ivan...
    volumeMounts: 
    - name: html
      mountPath: /var/www

  - name: web-server
    image: nginx:alpine
    ports:
    - containerPort: 80
    **volumeMounts**:
    - name: html
      mountPath: /usr/share/nginx/html
      readOnly: true
  volumes:
  - name: html
    emptyDir: {}

Docker hub 에 올릴 이미지 만들기

docker build -t ivaninitworld/fortune:latest .

이미지를 docker hub 로 올리기

docker push ivaninitworld/fortune:latest

fortune-pod 실행

k create -f fortune-pod.yaml

실행된 파드에서 출력값 가져오기

k exec fortune -c html-generator -- cat /var/www/index.html
k exec fortune -c web-server -- cat /usr/share/nginx/html/index.html
#
kimminhyeok@Ivans-Mac fourtune % k exec fortune -c web-server -- cat /usr/share/nginx/html/index.html
You will be reincarnated as a toad; and you will be much happier.
kimminhyeok@Ivans-Mac fourtune % k exec fortune -c html-generator -- cat /var/www/index.html         
You will be reincarnated as a toad; and you will be much happier.

Port-forward

k port-forward fortune 8080:80
#
kimminhyeok@Ivans-Mac fourtune % k port-forward fortune 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Handling connection for 8080
...
..
.

다른 터미널을 열어서

curl -s <http://localhost:8080>

#
kimminhyeok@Ivans-Mac k8s % curl -s <http://localhost:8080>
The Public is merely a multiplied "me."
                -- Mark Twain

 

728x90
반응형

'Dev. > Kubernetes & Helm' 카테고리의 다른 글

Kubernetes: ConfigMap  (0) 2023.09.18
Kubernetes: svc - pod 구조 이해  (0) 2023.09.17
Kubernetes: 리소스 생성해보기  (0) 2023.09.15
Kubernetes: 명령어와 익숙해지기  (0) 2023.09.15
Kubernetes: Intro  (0) 2023.09.12

댓글