Record
[k8s] 쿠버네트스 3 tier 구성 본문
쿠버네티스 환경에서 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 |