▶︎ 3Tier
보통 엔터프라이즈 웹 애플리케이션은 세 가지 종류의 서버로 구성된다.
- 프론트엔드 서비스를 제공하는 웹 서버
- 비즈니스 로직을 수행하는 웹 애플리케이션(WAS) 서버
- 데이터를 저장하는 데이터베이스 서버
이 세 가지 종류의 서버가 유기적으로 상호작용하며 하나의 애플리케이션으로 구성되는 것을
3Tier 아키텍처라고 부른다.
하지만 위 아키텍처의 경우 웹 애플리케이션 서버가 클라이언트에게 그대로 노출되어 있기에 보안상 위험이 뒤따른다.
그래서 nginx의 프록시 기능을 활용해서 백엔드 애플리케이션으로의 접근을 제한해야 한다.
아래와 같이 변경된 구조가 더 개선된 3Tier 구조라고 볼 수 있겠다.
‣ 구성도
- 프론트엔드 컨테이너는 HostOS의 80 포트로 접속
- 백엔드 컨테이너는 HostOS의 80 포트의
/api
경로로 접근- Nginx 서버에서 프록시되어 외부에서는 접근 불가
- 데이터베이스 컨테이너는 포트포워딩이 지정되지 않았기 때문에 외부에서는 접근 불가
- 내부 DNS 서버에 등록된 레코드를 통해 백엔드 컨테이너에서
leafy-postgres
로 접속
- 내부 DNS 서버에 등록된 레코드를 통해 백엔드 컨테이너에서
‣ 소스코드
프로젝트 clone
git clone https://github.com/JaehyoJJAng/3-tier-image-deploy
cd 3-tier-image-deploy
프로젝트 구조
tree -L 2 .
‣ 도커 네트워크
frontend, backend 네트워크 생성
docker network create leafy-frontend
docker network create leafy-backend
‣ 도커 로그인
${DOCKER_PASSWORD}
: DOCKER_PASSWORD 라는 변수에 도커 허브 패스워드 기입.${DOCKER_USER}
: DOCKER_USER 라는 변수에 도커 허브 유저명 기입.
# Docker login
echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USER}" --password-stdin
‣ Docker Run
A. leafy-frontend
Dockerfile 작성
#### Build Stage
# 빌드 이미지로 node:14 지정
FROM node:14 AS build
# 작업 디렉토리 지정
WORKDIR /app
# 라이브러리 설치 파일 복사
COPY package*.json .
# 라이브러리 설치
RUN npm ci
# 소스코드 전체 복사
COPY . .
# 소스코드 빌드
RUN npm run build
#### Production Stage
# 빌드 이미지로 nginx 지정
FROM nginx:1.21.4-alpine
# nginx config 파일 복사
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf.template
# 환경변수 설정
ENV BACKEND_HOST=leafy
ENV BACKEND_PORT=8080
# docker-entrypoint.sh 파일 복사
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# 빌드 이미지에서 생성된 dist 폴더를 nginx 이미지로 복사
COPY /app/dist /usr/share/nginx/html
# 컨테이너 포트 지정
ARG NGINX_PORT=80
EXPOSE $NGINX_PORT
# ENTRYPOINT 지정
ENTRYPOINT ["docker-entrypoint.sh"]
# COMMAND 지정
CMD ["nginx", "-g", "daemon off;"]
1. 도커 이미지 build & push
# build
docker build --tag yshrim12/leafy-frontend:latest .
# push
docker push yshrim12/leafy-frontend:latest
2. 컨테이너 실행
docker run -d -it --name leafy-front -p 80:80 yshrim12/leafy-fronend
3. leafy-front 컨테이너에 도커 네트워크 연결
docker network connect leafy-frontend leafy-front
docker network connect leafy-backend leafy-front
4. leafy-front 컨테이너 재시작
docker restart leafy-front
5. 컨테이너 로그 조회
docker logs leafy-front
B. leafy-backend
leafy-backend/Dockerfile
#### Build Stage
# 빌드 이미지로 OpenJDK 11 & Gradle 지정
FROM gradle:7.6.1-jdk11 AS build
# 작업 디렉토리 지정
WORKDIR /app
# 라이브러리 설치 파일 복사
COPY build.gradle settings.gradle ./
# gradle dependencies
RUN gradle dependencies --no-daemon
# 소스코드 전체 복사
COPY ./ ./
# Gradle 빌드 실행하여 JAR 파일 생성
RUN gradle clean build --no-daemon
#### Runtime stage
# 런타임 이미지로 OpenJDK 11-jre-slim 지정
FROM openjdk:11-jre-slim
# 작업 디렉토리 지정
WORKDIR /app
# 빌드 이미지에서 생성된 JAR 파일을 런타임 이미지로 복사
COPY /app/build/libs/*.jar ./leafy.jar
# 컨테이너 포트 지정
EXPOSE 8080
ENTRYPOINT ["java"]
CMD ["-jar", "leafy.jar"]
1. 도커 이미지 build & push
# build
docker build --tag yshrim12/leafy-backend:latest .
# push
docker push yshrim12/leafy-backend:latest
2. 컨테이너 실행
docker run -d -it --name leafy -p 8080:8080 \
--network leafy-backend \
-e DB_URL=leafy-postgres
yshrim12/leafy-backend
3. 컨테이너 로그 조회
docker logs leafy
C. leafy-postgresql
leafy-postgresql/Dockerfile
# PostgreSQL 13 버전을 베이스 이미지로 사용
FROM postgres:13
# init.sql 파일을 /docker-entrypoint-initdb.d/로 복사
# /docker-entrypoint-initdb.d/에 있는 sql문은 컨테이너 처음 실행 시 자동 실행됨.
COPY ./init/init.sql /docker-entrypoint-initdb.d/
# config/postgresql.conf 파일을 /etc/postgresql/postgresql.conf로 복사
# 기본 설정 파일을 덮어쓰기하여 새로운 설정 적용
COPY ./config/postgresql.conf /etc/postgresql/custom.conf
# 계정 정보 설정
ENV POSTGRES_USER=myuser
ENV POSTGRES_PASSWORD=mypassword
ENV POSTGRES_DB=mydb
# 컨테이너 포트 설정
EXPOSE 5432
CMD ["postgres", "-c", "config_file=/etc/postgresql/custom.conf"]
1. 도커 이미지 build & push
# build
docker build --tag yshrim12/leafy-postgres:latest .
# push
docker push yshrim12/leafy-postgres:latest
2. 컨테이너 실행
docker run -d -it --name leafy-postgres \
--network leafy-backend \
yshrim12/leafy-postgres
3. 컨테이너 로그 조회
docker logs leafy-postgre
4. 컨테이너 명령어 실행
docker exec -it leafy-postgres su postgres bash -c "psql --username=myuser --dbname=mydb"
5. 데이터 조회
$ mydb=# SELECT * FROM users;
$ mydb=# SELECT * FROM plants;
$ mydb=# SELECT * FROM user_plants;
$ mydb=# SELECT * FROM plant_logs;
‣ 도커 컴포즈
include
옵션을 사용하여 각 티어별 compose.yaml 분리
docker-compose.yaml
version: "3.9"
include:
- "composes/postgresql.yaml"
- "composes/backend.yaml"
- "composes/frontend.yaml"
networks:
leafy-backend:
driver: bridge
external: true
leafy-frontend:
driver: bridge
external: true
volumes:
mydata: {}
composes/postgresql.yaml
services:
leafy-postgres:
build: ../leafy-postgresql
image: leafy-postgres:5.0.0-compose
volumes:
- type: volume
source: "mydata"
target: "/var/lib/postgresql/data"
container_name: leafy-postgres
deploy:
resources:
limits:
cpus: '1'
memory: 256M
restart: always
networks:
- "leafy-backend"
composes/backend.yaml
services:
leafy-backend:
build: ../leafy-backend
environment:
- DB_URL=leafy-postgres
depends_on:
- "leafy-postgres"
container_name: leafy-backend
deploy:
resources:
limits:
cpus: '1.5'
memory: 512M
restart: on-failure
networks:
- "leafy-backend"
composes/frontend.yaml
services:
leafy-front:
build: ../leafy-frontend
image: leafy-front:5.0.0-compose
environment:
- BACKEND_HOST=leafy-backend
ports:
- 80:80
depends_on:
- "leafy-backend"
container_name: leafy-frontend
deploy:
resources:
limits:
cpus: '0.5'
memory: 64M
restart: on-failure
networks:
- "leafy-frontend"
- "leafy-backend"
▶︎ 파이프라인 구성
‣ 환경 변수 셋업
‣ leafy-frontend
.github/workflows/leafy-frontend.yaml
name: Frontend Build and Push
on:
push:
branches:
# main 브랜치에 push 될 때 워크플로우 실행
- main
paths:
# leafy-frontend 디렉토리에 변경점이 있을 경우에만 워크플로우 동작.
- 'leafy-frontend/**'
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: "1. Checkout Repository"
uses: actions/checkout@v2
- name: "2. Set up Docker buildx"
uses: docker/setup-buildx-action@v1
- name: "3. Login to dockerhub"
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: "4. Build and push"
uses: docker/build-push-action@v2
with:
context: ./leafy-frontend # Dockerfile이 있는 경로 지정
file: ./leafy-frontend/Dockerfile # Dockerfile 지정
# 이미지를 레지스트리에 배포
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/leafy-frontend:${{ github.sha }}
platform: linux/amd64,linux/arm64,windows/amd64
배포 시 leafy-frontend 디렉토리에 변경점이 있을 경우 위 워크플로우가 자동으로 실행됨.
‣ leafy-backend
.github/workflows/leafy-backend.yaml
name: Backend Build and Push
on:
push:
branches:
# main 브랜치에 push 될 때 워크플로우 실행
- main
paths:
# leafy-backend 디렉토리에 변경점이 있을 경우에만 워크플로우 동작.
- 'leafy-backend/**'
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: "1. Checkout Repository"
uses: actions/checkout@v2
- name: "2. Set up Docker buildx"
uses: docker/setup-buildx-action@v1
- name: "3. Login to dockerhub"
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: "4. Build and push"
uses: docker/build-push-action@v2
with:
context: ./leafy-backend # Dockerfile이 있는 경로 지정
file: ./leafy-backend/Dockerfile # Dockerfile 지정
# 이미지를 레지스트리에 배포
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/leafy-backend:${{ github.sha }}
platform: linux/amd64,linux/arm64,windows/amd64
배포 시 leafy-backend 디렉토리에 변경점이 있을 경우 위 워크플로우가 자동으로 실행됨.
‣ leafy-postgres
.github/workflows/leafy-postgres.yaml
name: DB Build and Push
on:
push:
branches:
# main 브랜치에 push 될 때 워크플로우 실행
- main
paths:
# leafy-postgresql 디렉토리에 변경점이 있을 경우에만 워크플로우 동작.
- 'leafy-postgresql/**'
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: "1. Checkout Repository"
uses: actions/checkout@v2
- name: "2. Set up Docker buildx"
uses: docker/setup-buildx-action@v1
- name: "3. Login to dockerhub"
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: "4. Build and push"
uses: docker/build-push-action@v2
with:
context: ./leafy-postgresql # Dockerfile이 있는 경로 지정
file: ./leafy-postgresql/Dockerfile # Dockerfile 지정
# 이미지를 레지스트리에 배포
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/leafy-postgresql:${{ github.sha }}
platform: linux/amd64,linux/arm64,windows/amd64
배포 시 leafy-postgresql 디렉토리에 변경점이 있을 경우 위 워크플로우가 자동으로 실행됨.