쿠버네티스는 메니페스트 파일을 통해 파드를 생성한다. 파드는 NginX와 Tomcat 두 종류를 사용하고, 그 두 종류의 파드를 서비스의 IP(클러스터 IP)를 기반으로 연동하게 될 것이다.

매니페스트 파일

쿠버네티스는 매니페스트(정의 파일)에 기재된 내용에 따라 파드를 생성한다. 매니페스트 파일의 내용을 쿠버네티스에 업로드하면 그 내용이 데이터베이스(etcd)에 ‘바람직한 상태’로 등록되는 것이다.

그리고 그 바람직한 상태로 서버 환경을 유지한다.

디플로이먼트

파드레플리카셋(ReplicaSet)에 대한 선언적 업데이트를 제공한다.

디플로이먼트에서 바람직한 상태를 설명하고, 디플로이먼트 컨트롤러(Controller)는 현재 상태에서 바람직한 상태로 비율을 조정하며 변경한다.

새 레플리카셋을 생성하는 디플로이먼트를 정의하거나 기존 디플로이먼트를 제거하고, 모든 리소스를 새 디플로이먼트에 적용할 수 있다.

디플로이먼트 매니페스트 파일의 구조

디플로이먼트의 메니페스트 파일을 작성해보겠다. 디플로이먼트의 스펙은 템플릿의 형태로 파드의 설정을 기재한다.

일단 대항목들부터 써보자.

apiVersion:    <-- API 그룹 및 버전
kind:          <-- 리소스 유형
metadata:      <-- 메타데이터
spec:          <-- 리소스 내용
  1. apiVersion: 이건 쿠버네티스 API의 버전을 나타낸다. 쿠버네티스에서 제공하는 여러 리소스들이 시간에 따라 발전하면서 API 버전도 변화하기 마련이다. 예를 들어, v1, apps/v1 같은 걸 여기에 적는다.
  2. kind: 여기에는 쿠버네티스에서 만들고자 하는 리소스의 종류를 적는다. 예를 들면 파드, 서비스, 디플로이먼트 같은 것들이 있다. 이 값에 따라 쿠버네티스가 어떤 타입의 리소스를 만들지 결정한다.
  3. metadata: 이 항목은 리소스에 대한 메타데이터 정보를 담고 있어. 주로 리소스의 이름, 네임스페이스, 레이블, 주석 등을 여기에 포함한다. 이 정보들은 리소스를 식별하고 관리하는 데 쓰인다
  4. spec: 가장 중요한 부분 중 하나야. 이 ‘spec’은 리소스의 상세한 사양을 정의한다. 예를 들어 pod를 만든다면, 이 안에 컨테이너의 이미지, 포트 설정 등을 적는다. 리소스 타입에 따라 필요한 spec 정보가 달라진다

메타데이터와 스펙

메타데이터에는 리소스의 이름이나 레이블(키-값 쌍의 형태로 기재되는 메타데이터)을 기재한다.

스펙은 리소스의 내용을 정의한다. ‘어떤 리소스를 만들 것인가’에 해당하는 부분이다.

그럼 이제 그 아래의 중항목과 소항목을 보자

apiVersion:
kind:
metadata:
  name:           <-- 중항목. 디플로이먼트이름
spec:
  selector:       <-- 중항목. 셀렉터가 선택할 관리대상 테이블
    matchLabels:  <-- 소항목. 셀렉터가 선택할 관리대상 테이블
  replicas:       <-- 중항목. 레플리카 수 설정
  template:       <-- 중항목. 템플릿(파드의 정보)
    metadata:     <-- 소항목. 파드의 메타데이터를 기재
    spec:         <-- 소항목. 파드의 스펙을 기재

셀렉터 설정

디플로이먼트가 특정한 레이블이 부여된 파드를 관리할 수 있도록 하는 설정이다. matchLabels: 뒤로 레이블을 기재한다. 이 레이블은 template 아래의 metadata에 기재된 것이다.

레플리카 설정

파드의 개수를 관리한다.

템플릿 설정

생성할 파드의 정보를 기재한다. 기재할 내용은 파드를 설정할 내용, 메타데이터 및 스펙과 거의 같다. 실제로 설정을 작성하다보면 spec을 두 번 작성한다거나 name이 어느 대상의 이름인지 헷갈리기 쉽다. 그림을 하나 첨부하겠다

쿠버네티스 디플로이먼트 구조

메타데이터, 스펙 기재 내용

템플릿 및의 메타데이터와 스펙 아래에 기재할 내용은 임의로 설정할 레이블과 컨테이너의 생성 내용이다.

    metadata:
      labels:
        app:         <-- 설정할 레이블
    spec:
      containers:    <-- 컨테이너 명
        - name:      <-- 컨테이너 이름
          image:     <-- 이미지 이름 및 버전
          ports:     <-- 접속 포트 번호
            - containerPort:   <-- 컨테이너 포트
          volumeMounts:        <-- 마운트할 볼륨 내용
            - name:            <-- 볼륨 이름
              mountPath:       <-- 마운트할 컨테이너 내의 볼륨을 마운트 한다.
              subPath:         <-- 마운트할 특정 파일만 정
      volumes:
        - name:
          configMap:
            name:

컨테이너의 설정 내용으로는 컨테이너의 이름과 접속 포트, 그리고 (필요하다면) 볼륨을 지정할 수 있다. 볼륨은 안 지정하는 경우도 꽤 있으나 이번에 WEB과 WAS를 연동해야하니 NginX 설정파일과 Tomcat 의 index.jsp 내용을 변경해야 되니 볼륨 내용도 추가해야한다.

volumeMounts : 컨테이너 내부에서 볼륨을 어떻게 마운트할지를 정의한다. name은 볼륨의 이름이고 mountPath 마운트할 컨테이너 내의 경로, subpath는 특정 파일만 정의한다.

volumes : 실제 볼륨의 소스를 정의한다. 마찬가지로 name에서 볼륨 이름을 정의하고 configMap에서 설정 데이터의 이름을 기재한다.

여기서 configMap이라는 생소한 단어가 또 나왔다.

ConfigMap은 쿠버네티스(Kubernetes)에서 설정 정보나 데이터를 저장하고 관리하는 데 사용되는 API 오브젝트다.

이것을 사용함으로써 애플리케이션 코드와 설정 데이터를 분리할 수 있어서 유지보수와 애플리케이션 구성이 훨씬 쉬워진다.

그럼 ConfigMap의 구성을 알아보자

apiVersion:
kind: ConfigMap
metadata:
  name:
data:

apiVersion : api 오브젝트 버전을 정의한다.

kind : ConfigMap은 이 오브젝트가 ConfigMap 타입임을 명시한다.

metadata : configmap의 이름과 마운트할 데이터를 각각 name과 data에서 정의한다.

WEB을 NginX로 쓰고 Tomcat을 WAS로 쓰려면 엔진엑스를 리버스 프록시로 설정해야하고, 그러려면 nginx.conf의 내용을 변경해야 한다.

이에 따라 ConfigMap 파일을 작성해주었다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  nginx.conf: |
    events {
      worker_connections  1024;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
        server {
            listen       80;
            server_name  localhost;
            location / {
              root   html;
              index  index.html index.htm;
              proxy_pass http://10.111.83.30:8080;
            }
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    }

설명하자면 쿠버네티스 API 버전은 v1이고, 메니페스트 종류를 ConfigMap으로, 이름을 nginx-config으로 설정한 것이다.

그리고 data에서 실제 nginx.conf 파일의 내용을 저장한다.

‘|’ 표시는 이제부터 이어지는 내용이 nginx.conf의 내용을 완전히 대체한다는 뜻이다. 여기서부터 작성되는 내용이 nginx.conf파일 내용의 전부가 된다.

여기에 Proxy_pass 내용을 넣어 <Tomcat의 서비스 IP>:8080으로 사용자의 요청을 전달하는 것이다.

그러면 ConfigMap도 정의했으니 이제 NginX 파드를 생성하기 위한 디플로이먼트 파일을 작성해 보겠다.

apiVersion: apps/v1          <--API 버전 설정
kind: Deployment             <--종류는 디플로이먼트
metadata:
  name: nginx-deployment     <--메타데이터: 디플로이먼트 이름 지정
spec:                        <--스펙
  selector:
    matchLabels:             <--셀렉터 레이블
      app: nginx000ex99      <--레이블 이름 설정
  replicas: 1                <--레플리카수 1개로 설정
  template:
    metadata:
      labels:
        app: nginx000ex99       <--똑같은 엔진엑스 레이블 사용
    spec:
      containers:
        - name: nginx000con01   <--엔진엑스 컨테이너 이름
          image: nginx:latest   <--이미지 및 버전
          ports:
            - containerPort: 80  <--접속 포트번호 설정
          volumeMounts:          <--볼륨 마운트
            - name: nginx-config-volume          <--붙이려는 configMap 이름
              mountPath: /etc/nginx/nginx.conf   <--마운트 하려는 엔진엑스 컨테이너의 경로
              subPath: nginx.conf
      volumes:                   <--파드에 붙이려는 볼륨
        - name: nginx-config-volume
          configMap:
            name: nginx-config   <--붙이려는 configMap 이름

이렇게 메니페스트 파일을 작성해 주었다.

여기서 볼륨 마운트를 한 부분을 보자.

volumeMounts: 밑에 name 쪽에서 ConfigMap 파일에서 작성한 ConfigMap의 이름을 지정해주었다. 그리고 mountPath에서 리눅스 기반의 컨테이너 내에서 nginx 구성파일의 경로를 지정해 주었다.

그리고 template밑의 spec항목 밑의 volumes에서 위에서 설정한 ConfigMap을 적용해 준 것이다.

이렇게 되면 NginX 컨테이너 하나가 포함된 Pod가 메니페스트 파일에서 설정한 레플리카의 개수 1개 생성된다.

그 파이 안에 컨테이너 내의 /etc/nginx/nginx.conf 라는 경로에서 configMap에서 작성한 그 nginx.conf 파일 내용이 적용이 된다. 그리고 메니페스트 파일이 정의한 ‘건강한 상태를 유지하기 위해’ 이 엔진엑스 파드의 개수를 항상 유지한다.

서비스 파일 작성

그럼 이어서 서비스 파일을 작성해보자.

디플로이먼트와 서비스는 거의 세트라고 생각해도 된다. 서비스의 메니페스트 파일은 디플로이먼트보가 간단하다. 서비스의 역할은 파드로 들어오는 요청을 관리하는 것 이기 때문에 설정 내용도 통신과 관련된 것이다.

apiVersion:
kind: Service
metadata:
  name:              <--서비스의 이름
spec:
  type:              <--서비스의 유형
  selector:
    app:
  ports:             <--서비스의 포트
    - port:          <--컨테이너 포트
      targetPort:    <--통신에서 사용되는 포트
      nodePort:      <--셀렉터 설정

유형(type 설정)

유형은 외부로부터 서비스에 어떤 유형의 IP 주소(또는 DNS)로 접근할지를 설정한다.

유형 이름내용
ClusterIP클러스터 ip를 통해 접근
NodePort워커 노드의 IP를 통해 서비스에 접근하도록 함
LoadBalancer로드밸런서의 IP를 통해 서비스에 접근
ExternalName파드에서 서비스를 통해 외부로 나가기 위한 설정

유형을 클러스터 IP로 설정하면 클러스터 IP를 통해 서비스에 접근한다. 클러스터 IP는 사설 IP 주소가 설정되어있어서 말 그대로 클러스터 내부의 통신에서만 사용 가능하다.

사용자를 웹 사이트에 접근시키기 위해서는, 유형 이름을 LoadBalancer 로 하고 로드밸런서의 IP 주소로 접근하게 한다. 실제로도 실무에서는 LoadBalancer로 설정하는 경우가 대부분이다.

여기서는 NodePort로 설정하면 워커 노드에 직접 접근할 수 있다. 워커노드가 직접 무언가를 처리하는 구성을 취했거나 개발 목적 등 특정 워커도드로 접근해야 할 경우에 사용한다.

이 실습에서는 로드밸런서가 없어서 NodePort를 사용하는 거다.

이러면 브라우저에서 서비스 메니페스트에서 지정한 워커 노드 포트로 접근하게 된다.

실제 서비스 메니페스트 파일을 작성해보자.

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort
  selector:
    app: nginx000ex99
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080

apiVersion, kind, metadata:

apiVersion: 오브젝트의 쿠버네티스 API 버전을 v1으로 설정했다.
kind: Service는 이 오브젝트가 서비스임을 명시한다.

metadata:
name: 이 서비스의 이름을 nginx-service로 정의한다.

spec:
type: 여기서 서비스의 타입을 NodePort로 설정한 것이다.
selector에서 app: app 라벨이 nginx000ex99인 파드들을 타겟으로 삼겠다는 의미이다. 이 서비스가 관리할 파드들을 어떻게 식별할지 정의한 것이다.

ports : 서비스의 포트 설정을 다룬다.

nodePort: 30080은 클러스터 외부에서 이 서비스에 접근할 때 사용할 포트를 지정한다.
즉, 클러스터 외부에서 NodeIP:30080을 통해 이 서비스에 접근할 수 있게 되는 것이다.

결론적으로, NginX를 실행하는 파드들을 nginx-service라는 이름의 서비스를 통해 관리할 수 있게 된다.

서비스 타입은 nodePort다. 외부에서 이 서비스에 접근하려면 클러스터의 노드 IP와 30080 포트를 사용해야 한다.

이렇게 서비스를 사용하면 파드들의 IP나 포트 변경에 영향을 받지 않고 안정적으로 트래픽을 관리할 수 있게 된다.

Tomcat 메니페스트 파일 작성

그럼 NginX의 모든 메니페스트 파일을 작성했으니 이제 Tomcat의 메니페스트 내용을 작성하자.

로컬 컴퓨터에서 브라우저로 접속을 했을 때 톰캣의 index.jsp 파일의 내용이 뜨게 해야되기 때문에 컨테이너에서 /usr/local/tomcat/webapps/ROOT/index.jsp 경로에 적용할 내용을 ConfigMap에서 작성해줘야 된다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: tomcat-index
data:
  index.jsp: |
    <%@ page contentType="text/html;charset=UTF-8" %>
    <!DOCTYPE html>
    <html>
    <head>
        <title>WEB-WAS 연동 성공</title>
    </head>
    <body>
        <h1>WEB-WAS 연동 성공</h1>
    </body>
    </html>

Tomcat 서비스의 디플로이먼트 파일 작성

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deployment
spec:
  selector:
    matchLabels:
      app: tomcat000ex99
  replicas: 1
  template:
    metadata:
      labels:
        app: tomcat000ex99
    spec:
      containers:
        - name: tomcat000con01
          image: tomcat:latest
          ports:
            - containerPort: 8080
          volumeMounts:
            - name: tomcat-index-volume
              mountPath: /usr/local/tomcat/webapps/ROOT/index.jsp
              subPath: index.jsp
      volumes:
        - name: tomcat-index-volume
          configMap:
            name: tomcat-index

volumeMounts 항목 밑의 mountPath: 항목에서 /usr/local/tomcat/webapps/ROOT/index.jsp 경로에 ConfigMap파일에서 작성한 index.jsp 파일 내용이 적용되게 만들었다. 위에서 nginx.conf를 configMap으로 정의한것과 마찬가지다.

Tomcat 서비스 메니페스트 파일 작성

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
spec:
  selector:
    app: tomcat000ex99
  ports:
    - port: 8080
      targetPort: 8080

포트번호를 port와 target포트를 모드 8080으로 지정했다.

이렇게 되면 위에 nginx.conf에서 서비스 IP:8080 으로 프록시 패스를 설정한 것에 따라 Tomcat 파드르 사용자의 요청이 넘어오게 된다.

이렇게 K8S의 6개의 메니페스트 파일을 작성해서 WEB과 WAS를 연동할 도구를 만들어 냈다. 필자는 이 메니페스트 파일의 내용을 모두 nginx-tomcat-deployment.yml이라는 한 파일에 작성하고, 각각의 내용을 —로 구분해 주었다.

이제 윈도우에서 powershell을 실행하여 이 메니페스트 파일 내용을 적용, K8S 파드를 생성하고 실행해주자.

kubectl apply -f C:\DockerANDk8s\kube_folder\nginx-tomcat_v2_folder\nginx-tomcat-deployment.yaml

Docker 데스크톱을 보면 이렇게 컨테이너들이 생성되어있다. 메니페스트 파일에서 정의한 내용에 따라 파드가 생성되고 그 파드안에 컨테이너가 생긴것이다.

쿠버네티스는 각 서비스 IP 기반으로 통신한다. 그래서 nginx.conf 파일에서 프록시 패스(Proxy_pass)를 설정할 때 Tomcat 서비스가 가지고 있는 클러스터 IP로 요청이 넘어가게 한 것이다.

아래 그림에서 클러스터 IP는 Kubernetes 클러스터 전체에서 사용되는 내부 IP 주소 범위를 뜻한다. 각 서비스는 이 클러스터 IP 범위 내에서 IP 주소가 정해진다.

서비스 IP를 알아내는 명령을 파워쉘에 쳐보자.

kubectl get services

여기서 나온 IP 들이 서비스 IP이다. 이 IP를 nginx.conf 파일의 프록시 패스에 적용해주어서 서비스가 실행되는 것이다.

맨 밑에 tomcat-service의 IP가 10.111.83.30이라고 나와있다.

그래서 nginx.conf 파일에서 proxy_pass http://10.111.83.30:8080; <– 이렇게 설정해준 것이다.

nginx의 노드 포트를 30080으로 설정해 주었으니 localhost:30080 으로 접속해서 테스트 해보자

이렇게해서 쿠버네티스 메니페스트 파일을 작성해서 NginX와 Tomcat을 연동해 보았다. 필자도 공부를 하면서 이것저것 복잡한 개념들이 생소한 것들이라 복잡한 기분을 느꼈으나 막상 해보면 이해가 금방 될 수도 있다.

다음에는 WEB과 WAS를 연동한 것에 이어서 DB(MariaDB)를 연동해 보겠다.

Regerence

https://www.yes24.com/Product/Goods/108431011

Leave a Reply

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다