AWS Cloud School 8기/Docker

57일차) 2025-03-21(앱배포-python, nginx)

eitherwho 2025. 3. 21. 12:38

파이썬 플라스크 앱 배포

git clone https://github.com/oolralra/smart


실습)

 이 앱을 컨테이너화하고 사설저장소에 push해서 테스트 해보세요!
- 파이썬 버전 3.9
- pip install -r requirements.txt: 패키지 설치
- gunicorn -b 0.0.0.0:8080 main:app: 앱을 실행하는 명령어. 모든 대역에 오픈 (-b 0.0.0.0:8080)
flask → gunicorn
fastAPI → unicorn
root@ubun-tem:~/smart# apt update -y && apt install -y python3-pip
root@ubun-tem:~/smart# pip install -r requirements.txt
root@ubun-tem:~/smart# vi Dockerfile
FROM python:3.9

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD [ "gunicorn", "-b", "0.0.0.0:8080", "main:app" ]
# CMD [ "python", "./main.py" ]

root@ubun-tem:~/smart# docker build -t python:1 .
root@ubun-tem:~/smart# docker run -dp 8081:8080 --name python-app python:1

root@ubun-tem:~/smart# docker run --name reg -dp 5000:5000 --restart=always -v /registry:/var/lib/registry/docker/registry/v2 registry:latest
root@ubun-tem:~/smart# docker tag python:1 211.183.3.150:5000/python:1
root@ubun-tem:~/smart# docker push 211.183.3.150:5000/python:1
root@ubun-tem:~/smart# vi /etc/docker/daemon.json
{
        "insecure-registries": ["211.183.3.150:5000"]
}
root@ubun-tem:~/smart# systemctl restart docker
root@ubun-tem:~/smart# docker push 211.183.3.150:5000/python:1
root@ubun-tem:~/smart# curl http://211.183.3.150:5000/v2/_catalog
{"repositories":["mynginx","python"]}
root@ubun-tem:~/smart# docker run -d -p 5003:8080 --name registry_web --restart=always --link reg -e REGISTRY_URL=http://211.183.3.150:5000/v2 -e REGISTRY_NAME=211.183.3.150:5000 hyper/docker-registry-web

풀이)

  1. 이미지 선택
  2. requirements.txt 복사
  3. pip install
  4. 소스코드 복사
  5. 실행

멀티스테이지 빌드

root@host:~# mkdir multi
root@host:~# cp -r sb_code multi
root@host:~# cd multu/sb_code
root@host:~# vi Docekrfile
# 1단계: 빌드
FROM maven:3.6.3-openjdk-8-slim AS builder
WORKDIR /app
COPY . .
RUN mvn clean package

# 2단계: 실행
FROM openjdk:8-alpine
WORKDIR /app
COPY --from=builder /app/target/springbootApp.jar app.jar
CMD ["java", "-jar", "app.jar"]

root@ubun-tem:~/multi/sb_code# docker build -t msb:1 .
root@ubun-tem:~/multi/sb_code# docker run -dp 8085:8085 --name mtest msb:1


실습)

첫번째 스테이지를 ubuntu:latest 로 하여 호스트에 존재하는 간단한 source-code.txt 파일을 넣은 후, 이 파일의 이름을 index.html바꿔서 nginx:alpine를 기반으로 하는 다음스테이지에 넣어서 배포해보세요.
root@host:~/multi# mkdir nginx
root@host:~/multi# cd nginx/
root@host:~/multi/nginx# echo source-code > source-code.txt
root@ubun-tem:~/nginx# vi Dockerfile
# 1단계: 빌드 (Ubuntu에서 파일 준비)
FROM ubuntu:latest AS builder
WORKDIR /app
COPY source-code.txt .
RUN mv source-code.txt index.html

# 2단계: 실행 (Nginx를 활용한 웹 서버)
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY --from=builder /app/index.html index.html

  • Docker 이미지 빌드 및 컨테이너 실행
docker build -t nginx .
docker run -dp 8080:80 --name nginxcon nginx


VUE로 만든 프론트엔드 멀티스테이지 빌드

root@host:~/multi/mginx# cd ..
root@host:~/multi# git clone https://github.com/oolralra/vue-fastapi.git
root@host:~/multi# cd vue-fastapi
  • frontend
root@host:~/multi/vue-fastapi/frontend# vi Dockerfile

root@host:~/multi/vue-fastapi/frontend# docker build -t vue:1 .
root@host:~/multi/vue-fastapi/frontend# docker run -dp 5656:80 --name web vue:1

  • backend

root@host:~/multi/vue-fastapi/frontend# cd ..
root@host:~/multi/vue-fastapi# cd backend/
root@host:~/multi/vue-fastapi/backend# vi Dockerfile 
root@host:~/multi/vue-fastapi/backend# docker build -t back:1 .
root@ubun-tem:~/multi/vue-fastapi/backend# docker run -dp 8000:8000 --name backend back:1

# 간단한 데이터가 들어있음

다시 프론트엔드로 돌아가서 소스코드를 보면,

프론트엔드에서 백엔드로 리버스 프록시를 걸고 --link backend로 설정

root@host:~/multi/vue-fastapi/backend# cd ..
root@host:~/multi/vue-fastapi# cd frontend/
root@host:~/multi/vue-fastapi/frontend# vi default.conf
  • 리버스 프록시 파일 내용

root@host:~/multi/vue-fastapi/frontend# vi src/components/Products.vue

root@host:~/multi/vue-fastapi/frontend# vi Dockerfile
FROM node:16 AS build
# node:16환경을 build로 리네임,별명

WORKDIR /app

COPY package*.json .
# 설치목록 복사

RUN npm install
# 설치목록 설치

COPY . .
# 소스코드 복사

RUN npm run build
# 빌드를 하면 dist폴더에 정적파일 생성

FROM nginx:alpine

COPY --from=build /app/dist /usr/share/nginx/html
# build라는 환경의 /app/dist, 즉 정적파일을 nginx의 웹루트디렉토리로 복사
COPY --from=build /app/default.conf /etc/nginx/conf.d/default.conf

# nginx는 알아서 실행된다. CMD 무필요

# Dockerfile의 22번째줄에 주석해제하고 /app/default.conf가 두 번 들어가 있는 부분 수정

root@ubun-tem:~/multi/vue-fastapi/frontend# docker build -t front:1 .
root@ubun-tem:~/multi/vue-fastapi/frontend# docker run -dp 80:80 --name web --link backend front:1


실습)

백엔드는 그대로 두고, 프론트엔드를 node:16으로 띄워서 백엔드와 연동해보세요!
프론트엔드앱이 사용하는 포트: 8080
node에서 vue앱을 동작시키기 위한 명령: npm run serve
root@ubun-tem:~/multi/vue-fastapi# cp -r frontend frontendnginx
root@ubun-tem:~/multi/vue-fastapi# ls
backend  frontend  frontendnginx
root@ubun-tem:~/multi/vue-fastapi# cd frontend
root@ubun-tem:~/multi/vue-fastapi/frontend# vi Dockerfile
FROM node:16 AS build
# node:16환경을 build로 리네임,별명

WORKDIR /app

COPY package*.json .
# 설치목록 복사

RUN npm install
# 설치목록 설치

COPY . .
# 소스코드 복사

CMD ["npm","run","serve"]

 

✅ vue.config.js 수정 (백엔드 프록시 추가)

  • /api로 들어오는 요청을 백엔드 컨테이너의 http://backend:8000으로 전달
  • changeOrigin: true → CORS 문제 해결
  • pathRewrite: { "^/api": "" }
    • 예) Vue에서 axios.get("/api/users") 요청 시 → http://backend:8000/users로 변환
const { defineConfig } = require('@vue/cli-service')

module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    proxy: {
      "/api": {
        target: "http://backend:8000", // 백엔드 컨테이너의 주소
        changeOrigin: true,
        pathRewrite: { "^/api": "" }
      }
    }
  }
});
root@host:~/multi/vue-fastapi/frontend# docker build -t vue:1 .
root@ubun-tem:~/multi/vue-fastapi/frontend# docker run --link backend -dp 8080:8080 --name web vue:1

풀이)

  • 방법1) 리버스프록시를 안쓰는 방법 → 백엔드를 보호해야 하는데, 이런 접근은 사실상 잘못된 방법
vi src/components/Products.vue

브라우저가 직접 찾아갈 수 있는 주소를 적어준다.

    • 방법2) 리버스프록시를 vue.config.js에서 구성해준다.
root@ubun-tem:~/multi/vue-fastapi/frontend# vi vue.config.js 
const { defineConfig } = require('@vue/cli-service')
  
module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    proxy: {
      "/api": {
        target: "http://backend:8000",
        changeOrigin: true,
        pathRewrite: { "^/api": "" }
      }
    }
  }
});

# 리버스프록시가 되어있으면 프론트엔드를 통해 백엔드를 찾아갈 수 있지만, 리버스프록시가 안되어있으면 브라우저가 직접 백엔드를 찾아가야 한다. (방법1)

localhost: 스스로한테 들어오는 가상 인터페이스 주소, loopback 0(127.0.0.1/8)