▶︎ 개요
쿠버네티스로 간단한 Django 웹 서비스를 배포하는 과정을 기록.
▶︎ 프로젝트 구조
Django 개발 서버 디렉토리 구조
├── django
│ ├── Dockerfile
│ ├── manage.py
│ ├── myapp
│ │ ├── asgi.py
│ │ ├── __init__.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ └── requirements.txt
├── docker-compose.yaml
└── nginx
├── conf
│ └── default.conf
└── Dockerfile
k8s 배포 서버 디렉토리 구조
├── create_secret.sh
├── django.yaml
├── ingress.yaml
├── nginx.yaml
├── postgres.yaml
└── README.md
▶︎ 사전 준비
- 외부로 배포하기 위해 Nginx Ingress Controller & metalLB 설치 필요
- 관련 작업 링크
postgresql DB 접속을 위해 django의 settings.py
을 아래와 같이 수정
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv('POSTGRES_DB','postgres'),
'USER': os.getenv('POSTGRES_USER','postgres'),
'PASSWORD': os.getenv('POSTGRES_PASSWORD','postgres'),
'HOST': os.getenv('POSTGRES_HOST','postgres-service'),
'PORT': int(os.getenv('POSTGRES_PORT',5432))
}
}
...
▶︎ 프로젝트 생성
- 해당 섹션의 하위 작업들은 모두 배포 서버(k8s)가 아닌 개발 서버에서 진행
Django 프로젝트 생성
# 가상환경 활성화
pyenv virtualenv 3.11.6 py3_11_6
pyenv activate py3_11_6
# Django 설치
pip install django
# 장고 프로젝트 생성
django-admin startproject myapp .
‣ 도커 이미지 생성 & 빌드
- django와 nginx 이미지만 빌드하여 도커 허브에 배포
- postgresql은 빌드된 이미지 없이 순정 이미지를 pull 받아서 띄울 것임.
• django
Dockerfile 작성
FROM python:3.11.6
ENV PYTHONDONTWRITEBYTECODE 1
WORKDIR /usr/src/app
COPY ./requirements.txt .
RUN pip install --upgrade pip && pip install -r requirements.txt
COPY . .
EXPOSE 8888
CMD ["gunicorn", "--bind", "0.0.0.0:8888", "myapp.wsgi:application"]
• nginx
Dockerfile 작성
FROM nginx:latest
COPY conf/default.conf /etc/nginx/conf.d/default.conf
CMD ["nginx", "-g", "daemon off;"]
nginx/nginx.conf
nginx 설정 파일 작성
upstream myweb {
server django-service; # 장고 서비스명 지정
}
server {
listen 80;
server_name myweb;
location / {
proxy_pass http://myweb;
}
}
• 이미지 빌드
django build & push
docker build --tag xxxx/k8s-django .
nginx build & push
docker build --tag xxxx/k8s-nginx .
▶︎ 서비스 배포
- 해당 섹션의 하위 작업들은 쿠버네티스 마스터 노드에서 진행
‣ secret 생성
create_secret.sh
#!/usr/bin/bash
kubectl create secret generic postgres-secret \
--from-literal=POSTGRES_DB=postgres \
--from-literal=POSTGRES_USER=postgres \
--from-literal=POSTGRES_PASSWORD=postgres \
--from-literal=POSTGRES_HOST=postgres-service \
--from-literal=POSTGRES_PORT=5432
# 실행권한 부여
chmod u+x create_secret.sh
# 스크립트 실행
bash create_secret.sh
‣ Django app 생성
django.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: django-deploy
spec:
replicas: 3
selector:
matchLabels:
app: django
template:
metadata:
labels:
app: django
spec:
containers:
- name: django
image: yshrim12/k8s-django:latest
ports:
- containerPort: 8888
env:
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_DB
- name: POSTGRES_HOST
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_HOST
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_PASSWORD
- name: POSTGRES_PORT
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_PORT
---
apiVersion: v1
kind: Service
metadata:
name: django-service
spec:
selector:
app: django
ports:
- protocol: TCP
port: 80
targetPort: 8888
- 특이사항
env
속성에 생성한 secret의 키를 매핑하였음.- Django 이미지에서
EXPOSE
된 포트가8888
이므로 컨테이너의targetPort
속성의 값을8888
로 지정하였음. - 서비스의
targetPort
또한 8888로 지정.
‣ nginx app 생성
nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: yshrim12/k8s-nginx
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
‣ postgresql app 생성
postgres.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres-deploy
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15.4
env:
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_DB
- name: POSTGRES_HOST
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_HOST
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_PASSWORD
- name: POSTGRES_PORT
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_PORT
---
apiVersion: v1
kind: Service
metadata:
name: postgres-service
spec:
selector:
app: postgres
ports:
- protocol: TCP
port: 5432
targetPort: 5432
- 특이사항
env
속성에 생성한 secret의 키를 매핑하였음.
‣ ingress 생성
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /django(/|$)(.*)
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
- 특이사항
- /django 경로의 하위 경로까지 인식되도록
(/|$)(.*)
를 추가로 작성하였음.
- /django 경로의 하위 경로까지 인식되도록
‣ 배포
kubectl apply -f .
외부 접속 테스트를 위해 nginx-ingress-controller
의 EXTERNAL-IP 조회
kubectl get svc/nginx-ingress-controller-1715592941 -n custom-nginx
# output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-ingress-controller-1715592941 LoadBalancer 10.96.31.137 192.168.219.40 80:30320/TCP,443:30629/TCP 27h
브라우저에 http://192.168.219.40/django
접속하여 정상적으로 접속 되는지 테스트
테스트 완료.
postgresql migrate 테스트
# 파드 조회 후 kubectl로 migrate 테스트
$ kubectl get pods -o name | grep 'django' \
| xargs -I{} kubectl exec {} -- python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
No migrations to apply.
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
No migrations to apply.
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
No migrations to apply.