Record

[k8s] 쿠버네트스 3 tier 구성 본문

CS/클라우드

[k8s] 쿠버네트스 3 tier 구성

now-record 2026. 2. 27. 17:40
반응형

쿠버네티스 환경에서 3 tier 구성을 해보려고 한다. 

 

web , was , db 이렇게 구성을 하고, db와 was, web의 파일의 경우 nfs서버를 두고 그 nfs서버에서 가져올 것이다. 

 

 

먼저 nfs 서버를 설정해준다. 

dnf install -y dnf-utils
#[공유할 디렉토리]  [허용할 대상](옵션들)
# 현재 전체한테 허용하는 중 , 동기처리
vi /etc/exports
/nfs_k8s *(rw,sync,no_subtree_check)

 

그리고 /nfs_k8s에서 우리 was , web, db파일을 각각 정의해준다. 

 

nfs_k8s/
├── db/
│   ├── mariadb_encoding.cnf
│   └── webtest_DB.sql
├── dynamic/
│   ├── board/
│   ├── member/
│   ├── database.py
│   ├── main.py
│   ├── model.py
│   ├── prestart.sh
│   └── requirements.txt
└── static/
    ├── css/
    ├── js/
    ├── edit.html
    ├── favicon.ico
    ├── index.html
    ├── login.html
    ├── register.html
    ├── view.html
    └── write.html

 

static에는 web에서 쓸 파일 , dynamic에서는 was에서 쓸 파일 db에서는 db에서 쓸 파일을 만들어놨다. 

 

그리고 모든 파일들을 nfs에서 처리해줄것이기 때문에 nfs-pvc와 nfs-pv를 만들어준다. 

# nfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-vol
  labels:
    type: nfs
spec:
  capacity:
    storage: 10Gi
  accessModes: ["ReadWriteMany"]
  nfs:
    server: 10.11.0.170
    path: /nfs_k8s
~
# nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  storageClassName: ""
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 5Gi
  selector:
    matchExpressions:
      - key : type
        operator: In
        values:
        - nfs

 

 

이제 web , was , db는 어쩻든 이 pv와 허가받는 pvc파일로 연결되어야한다.

NAME                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
persistentvolume/nfs-vol   10Gi       RWX            Retain           Bound    default/nfs-pvc                  <unset>                          52s

NAME                            STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/nfs-pvc   Bound    nfs-vol   10Gi       RWX                           <unset>                 52s

 

 

 

1. WEB파트 

web에서 쓸 config를 정의해보자 

# nginx-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-conf
data:
  default.conf: |
    server {
        listen       80;
        server_name  localhost;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        location /api/ {
            # 여기서 was-service는 나중에 만들 WAS의 서비스 이름
            proxy_pass http://was-service:80;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }

 

안에 들어갈 설정들을 conf로 해결해준다. 

# front.yaml (수정본)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-web
  template:
    metadata:
      labels:
        app: nginx-web
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        volumeMounts:
          # nfs에서 가져오고 이쪽 경로로 넣어줌
        - name: nfs-vol
          mountPath: /usr/share/nginx/html
          subPath: static
          # nginx-conf에 있는 default.conf안에 있는 걸 읽어서 이 컨테이너의 설정을 바꿈
        - name: config-vol
          mountPath: /etc/nginx/conf.d/default.conf
          subPath: default.conf
        #----------------------------------------
        # volume 먼저읽음 volume에 pvc, configMap
      volumes:
      - name: nfs-vol
        persistentVolumeClaim:
          claimName: nfs-pvc

      - name: config-vol
        configMap:
          name: nginx-conf

 

끝내 여기서는 nfs와 앞에서 해준 config 파일을 가져와서 해결해줌 volumes에서 2개를 받고 containers안에서 각각 어디서 가져와서 어디에 적용할건지를 작성해줌 

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: LoadBalancer    # 여기를 바꿈!
  selector:
    app: nginx-web      # Deployment의 labels와 일치해야 함
  ports:
    - protocol: TCP
      port: 80          # 외부에서 접속할 포트 (http://외부IP)
      targetPort: 80    # Pod(컨테이너) 내부에서 열려있는 포트

 

이렇게 service로 loadbalancer를 할 수 있는 이유는 metallb로 externel ip를 할당해줬기 때문이다. 

#metallb-config.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: test-pool
  namespace: metallb-system
spec:
  addresses:
  - 10.11.0.200-10.11.0.210
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: l2-broadcast
  namespace: metallb-system
spec:
  ipAddressPools:
  - test-pool

 

 

원래라면 status에 running이 들어가야 하는데 지금 was쪽을 안켜줘서 config에서 문제가 생겼다. 

 

was쪽을 키면 running으로 바뀐다. 

 

2. WAS파트

deploy

apiVersion: apps/v1
kind: Deployment
metadata:
  name: was-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: was-api
  template:
    metadata:
      labels:
        app: was-api
    spec:
      containers:
      - name: fastapi
        image: tiangolo/uvicorn-gunicorn-fastapi:python3.9
        ports:
        - containerPort: 80  # 이 이미지의 기본 포트는 80이야
        volumeMounts:
        - name: nfs-vol
          mountPath: /app    # 컨테이너 안에서 코드가 돌아갈 위치
          subPath: dynamic   # NFS(/k8s_nfs/) 내부의 dynamic 폴더만 가져옴
      volumes:
      - name: nfs-vol
        persistentVolumeClaim:
          claimName: nfs-pvc  # 아까 프론트에서 썼던 그 PVC 이름
~

 

service

apiVersion: v1
kind: Service
metadata:
  name: was-service      # Nginx의 proxy_pass 이름과 일치 필수!
spec:
  type: ClusterIP        # 내부 통신용이니까 ClusterIP면 충분함
  selector:
    app: was-api         # Deployment의 label과 일치
  ports:
    - protocol: TCP
      port: 80           # Nginx가 접속할 포트
      targetPort: 80     # 컨테이너 포트

내부 통신이기때문에 로드밸런싱을 하지 않아도 됌 

 

그리고 현재 외부 사용자 80 -> web server_80으로 받음 -> proxy(was):80 -> was에서 80으로 받고 있어서 다른 ip의 80이기때문에 같은 80이여도 상관없다. 

 

그리고 was를 쓰다보면 저거 말고도 다른 패키지를 깔아줘야하는데 

nfs폴더에 prestart,sh랑 requirements.txt를 통해서 설치를 할 수 있게 해준다. 

 

 

이렇게 켜주면 

 

가입에 실패한다. 이유는 db와 연결이 안되있기 때문, 그렇기 때문에 db를 켜주고 was랑 연결해줘야한다. 

 

# db-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mariadb-config
data:
  MYSQL_USER: "kedu"
  # NFS 내의 상세 경로를 변수화해서 관리하면 나중에 편함
  INIT_SQL_PATH: "db/webtest_DB.sql"
  ENCODING_CNF_PATH: "db/mariadb_encoding.cnf"
# db-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mariadb-secret
type: Opaque
data:
  # P@ssw0rd를 base64로 인코딩한 값
  MYSQL_ROOT_PASSWORD: "UEBzc3cwcmQ="
  MYSQL_PASSWORD: "UEBzc3cwcmQ="

 

nfs서버에 webtest_db정보와 한글 인코딩해야하는 파일을 config로 넣어두고 secret으로 db password를 설정한다. 

# db-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mariadb
spec:
  serviceName: "db-service"
  replicas: 1
  selector:
    matchLabels:
      app: mariadb
  template:
    metadata:
      labels:
        app: mariadb
    spec:
      containers:
      - name: mariadb
        image: mariadb:latest
        envFrom:
        - configMapRef:
            name: mariadb-config
        - secretRef:
            name: mariadb-secret
        ports:
        - containerPort: 3306
        volumeMounts:
        # NFS의 db/ 폴더에서 직접 파일을 찍어서 꽂아줌
        - name: nfs-vol
          mountPath: /docker-entrypoint-initdb.d/webtest_DB.sql
          subPath: db/webtest_DB.sql
        - name: nfs-vol
          mountPath: /etc/mysql/conf.d/mariadb_encoding.cnf
          subPath: db/mariadb_encoding.cnf
      volumes:
      - name: nfs-vol
        persistentVolumeClaim:
          claimName: nfs-pvc

 

 

모두가 running상태이다 이제 될까? 

 

이러면 log를 봐야한다.

kubectl logs mariadb-0

2026-02-27  8:26:48 0 [Note] mariadbd: Event Scheduler: Loaded 0 events
2026-02-27  8:26:48 0 [Note] mariadbd: ready for connections.
Version: '12.2.2-MariaDB-ubu2404'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution
2026-02-27  8:29:32 3 [Warning] Access denied for user 'kedu'@'%' to database 'WebTest'

 

db에 권한을 주지 않아서 생긴 문제이다. 

root@master00:~/3tier# kubectl exec -it mariadb-0 -- /bin/bash
root@mariadb-0:/# mariadb -u root -p
MariaDB [(none)]> GRANT ALL PRIVILEGES ON *.* TO 'kedu'@'%';
MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.001 sec)

 

이제 될까?

 

이제 되는것을 볼 수 있다. 

 

하지만 이 설정대로라면 만약에 db-pod가 꺼지면 설정이 다 날라간다. 그래서 따로 nfs에 이 내용들을 저장해줘야 한다. 

 

그건 다음시간에 알아보도록 하자 

'CS > 클라우드' 카테고리의 다른 글

AWS 기초  (0) 2026.04.01
[k8s] 쿠버네티스 resource 관리  (0) 2026.03.03
[K8s] 쿠버네티스 사용 1  (0) 2026.02.26
[K8s] 쿠버네티스 설치  (0) 2026.02.25
[K8s] 쿠버네티스란 ?  (0) 2026.02.24