사프를 개발하면서 vercel → netlify → amplify → ec2로 배포를 하게 되었는데, 제로인 EC2에서 어떻게 https 배포까지 할 수 있었는지를 설명하고자 합니다.
제가 하고 있는 사이드 프로젝트는 next를 이용해서 백엔드와 프론트엔드를 둘다 구현하고 있고, 대용량의 text를 gpt를 이용하여 다루고 있기 때문에, api call 한번에 3~5분정도 걸립니다.
그런데 vercel, netlify같은 경우는 api call의 timeout을 제한합니다. 그래서 EC2로 직접 배포하는 길을 선택했습니다.
우선 docker stack
을 이해하기 위해서는 docker swarm
에 대해서 조금 알아야 합니다.
docker swarm
은 컨테이너 오케스트레이션 이라고 하는 거라고 하는데, 맨 처음 봤을 때 이해가 안갑니다.
간단하게 여러대의 호스트를 운영 및 관리할 수 있게 해주는 도구라고 생각하시면 좋습니다.
이렇게 여러개의 호스트를 한개의 매니저가 관리할 수 있도록 도와주는 도구라고 생각하시면 편합니다.
그럼 docker stack
은 무엇이냐?
stack은 service(swarm이 아닌 docker에서는 container라고 부르는 친구)의 묶음입니다.
한 서비스를 구현할 때, 여러 기능이 필요하면 여러가지 image를 준비해서 stack으로 묶는것이지요.
그럼 여기서 의문이 드실겁니다.
docker compose도 어차피 container 묶어놓는놈인데 왜 굳이 stack을 씀?
이유는 간단합니다!
docker compose
는 실행 만이 역할입니다. 만약 중간에 컨테이너가 죽어도 아무 작업을 할 수 없다는 것입니다.
docker stack은 docker swarm에서 컨테이너가 죽었을 때의 대응 혹은 모니터링같은 작업을 할 수 있습니다. 그리고swarm에서 노드(컨테이너)를 여러대 띄워 두었다면, 안정적으로 배포할 수 있게 순차적으로 노드를 업데이트하도록 할 수 있습니다.
한마디로 정리하자면, stack은 compose에 확장성과 안정성이 추가되어 있는 버전입니다. (물론 지금 제 환경에 그런게 되어있다는건 아닙니다. 추후 작업 예정 ^^)
caddy는 간단하게 reverse proxy용 nginx입니다. (간단하죠?)
nginx를 선택하지 않은 이유는 nginx의 reverse proxy 세팅보다 caddy의 세팅이 훨씬 간단했기 때문입니다.
다른분들이 caddy를 이용하는 이유는 SSL인증서를 자동으로 발급 및 재발급 해주기 때문인데, 저는 aws route53에서 직접 ip를 연결해주고 있기 때문에 이건 조금 논외 ㅎㅎ..
만약 인증서가 필요하시다면 https://blog.jhyeom.com/caddy-server <- 이 글을 참고해 주세요. 정리가 잘 되어 있습니다.
우선 EC2를 새로 생성 하겠습니다.
설정은 기본적으로 세팅되어 있는것을 그대로 두고, key pair로 접속할 수 있게 key pair만 만들어서 생성해 주세요.
그리고 key pair로 인스턴스에 접근해줍니다.
아마 새로 key pair를 생성하셨으면, 다운로드 받으셨을 겁니다.
터미널에서 그 pem 파일이 있는곳으로 가주시고,
인스턴스 상세 페이지에서 연결 을 눌러주세요.
그럼 이런 화면이 나오는데, SSH 클라이언트를 선택하고 아래 프로세스를 따라하여 인스턴스에 접속해주세요.
우선, docker 공식문서에 적힌것처럼 docker를 설치 하겠습니다
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
# 실질적인 install
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
이 명령어가 모두 수행되면, docker가 install 됩니다.
그리고 docker는 접근 권한이 없어서 docker 명령어들이 permission denied가 뜰텐데,
sudo groupadd docker
sudo gpasswd -a $USER docker
newgrp docker
로, docker를 권한 추가 해줍니다.
아래 명령어로 swarm을 설정해줍니다.
swarm을 설정해주어야 stack을 사용할 수 있습니다.
docker swarm init
여러분들이 docker를 이용해서 배포를 하는 방법에는 github에서 code를 pull해서 docker build 후에 그 image로 stack을 만들어서 해도 되지만, 저는 거-대한 사이즈의 node_modules와 오래 걸리는 install을 굳이 하고싶지 않았습니다.
그래서 Docker Hub에 image를 push해서 ec2 인스턴스에서 pull 해오도록 하겠습니다. (docker image push는 이 글을 확인해주세요. 참고로 이미지 버전은 latest로 하는게 편합니다.)
그래서 여러분들이 Docker Hub에 push를 했다는 가정 하에 진행 하겠습니다.
만약 hub에 올리실 때, image가 private이면 docker login이 필요합니다.
docker login -u [ID]
하여, password를 정상적으로 입력하시면 로그인에 성공합니다.
이제 올리신 이미지를 pull 하여야 합니다.
docker hub에 정상적으로 올리셨으면, 저런 버튼이 있을겁니다.
누르시고 ec2 인스턴스에서 복붙, 실행 시켜주세요.
성공 하셨으면, 아래와 같이 뜹니다.
그리고 저희가 사용할 caddy도 docker image를 pull하겠습니다.
docker pull caddy:2-alpine
우선 원하는 위치에 Caddyfile 을 만들겁니다.
저는 /data/caddy 에 생성했습니다.
sudo mkdir /data/caddy
sudo mkdir /data/caddy/data
sudo vi Caddyfile
# sudo로 안하면 권한 에러납니다.
# /data/caddy/Caddyfile
[HOSTNAME] {
reverse_proxy web:3000 # 프로젝트가 뜨는 port 입력
}
docker stack이 좋은 이유가, docker-compose.yml 파일(3버전 이상부터) 호환되어서 좋습니다.
아래 명령어를 입력하시고
vi docker-compose.yml
아래와 같이 작성하겠습니다
networks:
proxy:
driver: overlay
services:
web:
image: [IMAGE_NAME]
ports:
- target: 3000 # 프로젝트가 실행되었을 때의 port를 입력해주세요.
published: 3000
protocol: tcp
mode: host
networks:
- proxy
caddy:
hostname: [HOST_NAME] # 배포되었을 때의 host를 입력해주세요.
image: caddy:2-alpine
restart: unless-stopped
ports:
- target: 443
published: 443
protocol: tcp
mode: host
- target: 80
published: 80
protocol: tcp
mode: host
networks:
- proxy
volumes:
- /data/caddy/Caddyfile:/etc/caddy/Caddyfile
- /data/caddy/data:/data
- /data/caddy/config:/config
docker-compose와 다르게, docker stack은 deploy라는 명령어로 실행합니다.
docker stack deploy -c ./docker-compose.yml [NAME]
이 명령어가 정상적으로 수행되고 나면, container가 2개 뜹니다
docker ps # 로 확인하기
저는 aws의 route53에 도메인을 연결해두어서 SSL같은 세팅을 하지 않아도 괜찮았습니다. (SSL 인증을 직접 하는 케이스는 나중에 따로 기술하겠습니다)
EC2의 public IP를 route53의 라우팅에 연결만 하면 되는데요.
우선 생성하신 EC2 인스턴스의 퍼블릭 IP를 복사합니다.
그리고 route53의 호스팅 영역 페이지에 들어가셔서 레코드 생성을 클릭합니다
그러면 아래와 같이 페이지가 나오는데, 값 부분에 퍼블릭 IP를 입력하시고, 레코드 생성을 눌러주세요.
레코드가 생성되고 나서 시간이 조금 지나고 호스트에 접속 하시면 페이지가 정상적으로 뜨는걸 확인하실 수 있을겁니다.
프론트도 하고자 하면 할 수 있다!
그리고 제 사프 이력서 기반으로 면접질문 만들어 주는 서비스인데 많은 관심 부탁드립니다.
만약 이 글에 문제가 있거나 질문이 있으시면 서스럼 없이 댓글 부탁드립니다.
전국의 모든 프론트 여러분 화이팅하세요.
감사합니다.