AKS 클러스터 구축 - 이전 자료를 확인하여 주시기 바랍니다. 링크
frontend (react) - 저는 프론트 엔드로 react를 선택하였고 nginx를 이용할 예정입니다. github에 있는 crud를 간단하게 구축해놓은 소스를 이용하여 조금 수정하여 사용하였습니다. 출처는 링크를 참조해 주시기 바랍니다
backend server (go) - gin-gonic과 gorm을 이용한 백엔드 서버를 구축하여 crud api server를 구축하여 사용하였습니다.
DB (Azure Database for mysql)
가장 먼저 해야할 내용은 front와 back 서버를 docker image로 만드는 것입니다. 이를 위해 Dockerfile을 생성합니다.
#Go server Dockerfile
FROM golang:1.18-alpine
WORKDIR /app
COPY . ./
RUN go mod download
RUN go build -o /goserver
EXPOSE 8081
CMD [ "/goserver" ]
프론트 엔드는 먼저 nginx.conf파일과 .env.production 파일을 생성하고 적용한 후에 Docker image로 만드는 작업을 진행하였습니다. .env.production은 package.json과 같은 위치에 두었습니다.
.env.production file
REACT_APP_URL=/api
그리고 이를 적용하기 위해 env-cmd를 이용하여 package.json에 적용하는 방식으로 진행하였습니다. env-cmd는 npm으로 설치하였습니다.
또한 GET 호출을 하는 부분에 URL을 아래 사진과 같이 변경하였습니다. 이렇게 하면 /api/crud로 호출이 진행되게 됩니다.
이제 nginx.conf 파일을 생성합니다. 저는 ./conf/nginx.conf 위치에 두었습니다. 아래 backend:8081 부분은 후에 service를 생성할 때 지정할 svc의 이름과 포트번호 입니다. 또한 /api 부분의 rewrite를 통하여 /api 부분을 제거한 이후 부분으로 백서버와 소통이 진행되게 됩니다. 따라서 실제로 백엔드로 전달되는 부분은 /crud로 진행되게 됩니다.
upstream backend {
server backend:8081;
}
server {
listen 80;
server_name frontend;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri /index.html;
}
location /api {
rewrite ^/api(.*)$ $1?$args break;
proxy_pass http://backend;
}
}
이제 프론트에 대한 Dockerfile을 생성합니다.
FROM node:16.18-alpine as builder
WORKDIR /app
COPY . ./
RUN npm i
RUN npm run build
FROM nginx
COPY conf/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/build/. /usr/share/nginx/html
각각의 Dockerfile을 생성하였다면 docker build 명령어를 이용하여 빌드를 진행합니다. 이후 docker hub로 push까지 진행하였습니다.
docker build -t DockerHubId/이름:태그 Dockerfile위치
docker push DockerHubId/이름:태그
이제 kubernetes에 배포하기 위한 yaml 파일을 생성합니다.
배포해야할 내용은 deployment 2개와 service 2개입니다.
먼저 web server에 대한 deployment 파일입니다.
아래와 같이 replicas로 pod의 수를 결정할 수 있으며 memory와 cpu도 제한할 수 있습니다.
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 3
selector:
matchLabels:
app: frontend
version: v1
template:
metadata:
labels:
app: frontend
version: v1
spec:
containers:
- name: frontend
image: DockerID/name:tag
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "125m"
limits:
memory: "128Mi"
cpu: "250m"
이후 service.yaml파일을 생성합니다. 서비스는 NodePort, LB, clusterip등으로 구성이 가능하며 default는 clusterip입니다. azure의 서비스를 같이 이용하기 위해 LB로 생성하였고 이 서비스를 apply하게 되면 azure에 LB가 생성되게 됩니다.
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
type: LoadBalancer
ports:
- port: 80
selector:
app: frontend
version: v1
이어서 api서버의 yaml파일입니다. yaml파일은 Deployment와 service를 함께 배포할 수 있으며 service의 annotations를 이용하여 internalLB도 생성이 가능합니다.
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 1
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: Dockerhubid/name:tag
ports:
- containerPort: 8081
name: app
---
apiVersion: v1
kind: Service
metadata:
name: backend
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
spec:
type: LoadBalancer
ports:
- port: 8081
selector:
app: backend
이제 kubectl 명령어로 배포를 진행합니다. 먼저 연결이 되어있는지 확인하기 위해서 node를 확인합니다.
노드가 확인이 된다면 apply를 통하여 배포를 진행합니다.
kubectl apply -f yaml파일
모든 파일을 배포하였다면 get 명령어를 통하여 배포 상태를 확인합니다.
kubectl get svc
kubectl get po -o wide
kubectl describe po pod이름
배포 내용을 보시면 해당 external ip가 생성이 됩니다. 해당 external ip로 접근을 해보면 정상적으로 동작하는 것을 확인할 수 있습니다.
물론 콘솔에서도 LB와 k8s의 리소스들에 대한 확인이 가능합니다.
react를 처음으로 사용하는 것이다보니 여러 문제가 있었는데 그 중 가장 어려웠던 부분이 proxy에 대한 부분이였습니다. 기존에는 package.json에 proxy로 적용을 하여 진행하였었는데 build를 진행하면서 package.json에 대한 proxy가 적용이 되지 않는 것을 모르고 있었습니다. 그래서 npm의 http-middleware를 적용해 보거나 내부에 소통을 확인, request url을 변경, goserver의 문제인것인가 싶어서 goserver의 내용을 변경해보는 등 여러모로 많은 시도를 했었고 모든 시도는 실패하였습니다. 이후 더 찾아보면서 해결 방법을 발견하여 진행하여 성공하였습니다. 성공을 하긴 했지만 이 방법이 가장 좋은 해답인지는 확신하지 못하는 상태입니다.
저번과 마찬가지로 az group delete를 이용하여 리소스 그룹을 제거하거나 kubectl delete -f yaml파일이름 을 이용하여 pod를 제거하거나 여러가지 방법이 있습니다.
귀찮으니 그룹을 날립니다