쿠버네티스를 사용하다보면, Web을 운영하는 파드와 DB를 운영하는 파드가 연결되어야 하는 상황이 생깁니다.
보통 DB의 경우 관리형 AWS RDS같은 관리형 데이터베이스를 사용하지만, 직접 파드를 운영하여 연결하는 방법을 정리하고자 합니다.
크게 2가지 방법으로 연결을 시도해 봤습니다.
- Sidecar 패턴
- 2개의 Service
Sidecar 패턴
가장 먼저 Sidecar패턴입니다.
하나의 파드 안에 2개의 컨테이너, 즉 DB와 Web server 컨테이너가 같이 존재하는 구조입니다.
이를 통해서 구현하면 같은 노드에 할당되어 같은 ip주소를 갖게 되어 localhost를 이용해서 연결이 가능합니다.
아래는 Sidecar 패턴의 연결 방법입니다.
fastapi-container의 env 를 보면, DB_HOST가 localhost로 되어 있습니다.
# service
apiVersion: v1
kind: Service
metadata:
name: sidecar-svc
spec:
ports:
- port: 80
targetPort: 8000
selector:
app: sidecar
type: LoadBalancer
# deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: sidecar-deployment
labels:
app: sidecar
spec:
selector:
matchLabels:
app: sidecar
strategy:
type: Recreate
replicas: 1
template:
metadata:
name: sidecar-pod
labels:
app: sidecar
spec:
containers:
- image: fast:0.1
name: fastapi-container
ports:
- containerPort: 8000
env:
- name: MYSQL_ROOT_PASSWORD
value: 'password'
- name: MYSQL_HOST
value: 'localhost' # localhost사용
- name: MYSQL_DATABASE
value: 'mysql-db'
- image: mysql:8.0.28
name: mysql-container
env:
- name: MYSQL_ROOT_PASSWORD
value: 'password'
- name: MYSQL_DATABASE
value: 'mysql-db'
ports:
- containerPort: 3306
이렇게 설정하는 것은 구현은 가능하지만, MSA구조에서 scale up 할 때 불편함을 느끼게 됩니다.
하지만 간단한 웹구조에서 유용하게 사용될 듯 합니다.
##$# 각각 다른 Service를 이용한 연결
다음 구조는 서로 다른 서비스끼리의 연결입니다.
위와 같은 경우는 설정한 DB service name을 통해서 연결이 가능한 구조입니다.
각각 하나의 Pod 안에 각각의 container를 설정하고, 이를 deployment 와 service로 묶습니다.
이후 DB service 와 Web service가 연결되도록 설정합니다.
아래는 사용한 예시 코드입니다.
fastapi deployment의 spec.template.spec.env 의 MYSQL_HOST와
mysql service의 metadata.name 이 같음을 주목하세요.
# service
apiVersion: v1
kind: Service
metadata:
name: fastapi-svc
spec:
ports:
- port: 80
targetPort: 8000
selector:
app: fastapi
type: LoadBalancer
---
apiVersion: v1
kind: Service
metadata:
name: mysql-svc # Mysql service name
labels:
app: mysql
spec:
selector:
app: mysql
type: NodePort
ports:
- port: 3306
# fastapi deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: fastapi
labels:
app: fastapi
spec:
selector:
matchLabels:
app: fastapi
strategy:
type: Recreate
replicas: 1
template:
metadata:
name: fastapi
labels:
app: fastapi
spec:
containers:
- image: fast:0.1
name: fastapi
ports:
- containerPort: 8000
env:
- name: MYSQL_ROOT_PASSWORD
value: 'password'
- name: MYSQL_HOST
value: 'mysql-svc' # Mysql service name
- name: MYSQL_DATABASE
value: 'mysql-db'
---
# DB deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-deployment
labels:
app: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql:8.0.28
name: mysql-pod
env:
- name: MYSQL_ROOT_PASSWORD
value: 'password'
- name: MYSQL_DATABASE
value: 'mysql-db'
ports:
- containerPort: 3306
ports name을 통해서 연결은 안되나요?
제가 헷갈렸던 내용 중 하나입니다. Docker의 경우 docker-compose에서 network를 생성하고 이를 브릿지를 통해서 연결하는 경우가 생각 날 것입니다.
그렇다면 k8s에서 ports name을 설정하고 이를 통해 연결 할 수 는 없을 까요…?
# db container
- image: mysql:8.0.28
name: mysql-container
env:
- name: MYSQL_ROOT_PASSWORD
value: 'password'
- name: MYSQL_DATABASE
value: 'mysql-db'
ports:
- name: db-port # port name 설정
containerPort: 3306
apiVersion: v1
kind: Service
metadata:
name: mysql-svc
labels:
app: mysql
spec:
selector:
app: mysql
type: NodePort
ports:
- port: 8000
targetPort: db-port # port name으로 설정
제가 얻어낸 결과는 다음과 같습니다.
ports의 name은 네트워크가 아닌 port를 맵핑하기 위한 내용인 듯합니다.
위와 같이, 설정한 name을 퉁해서 port를 설정할 수 있었습니다.