오늘은 docker를 이용하여 AWS EC2에 react앱을 배포해 보겠습니다. nginx 또한 사용할 예정입니다.(AWS EC2에 관해서는 따로 다루지 않을 예정)
시작하기전 docker의 간단한 명령어와 docker가 설치가 되어 있어야 합니다.(docker-compose 포함)
터미널창에 npx create-react-app ./
커맨드를 입력한 후 react 앱을 실행시키는 방법은 npm run start
로 실행을 시킬 수 있습니다. 코드를 약간 추가 해보겠습니다.
src > App.js
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
<a href="https://velog.io/@wmc1415">블로그 주소</a> //제 블로그 주소
</header>
</div>
);
}
export default App;
간단히 코드를 추가한 후 Dockerfile 및 docker-compose 파일을 작성하도록 하겠습니다.
//Dockerfile
// nginx가 제공을 해줄 빌드 파일들을 생성하는 코드
FROM node:12 as builder # node 12버젼사용 / build파일임을 명시
WORKDIR /app # working dir를 /app으로 설정
COPY ./package*.json ./ # 먼저 package.json/ package.lock.json 파일을 복사
RUN npm install # npm install
COPY . . # 로컬에 있는 모든 파일을 복사
RUN npm run build # 빌드
FROM nginx
EXPOSE 3001
COPY ./defalut.conf /etc/nginx/conf.d/default.conf # 로컬에 있는 default.conf 파일을 도커 /etc/nginx/conf.d/defalut.conf로 복사
COPY --from=builder /app/build /usr/share/nginx/html # 위에서 생성한 build 파일을 /usr/share/nginx/html로 복사
version: "3"
services:
frontend: # 이름은 어떤걸로 지정해도 상관없음
build:
dockerfile: Dockerfile # dockerfile이름
context: ./ # 도커파일 위치 명시
volumes:
- /app/node_modules #도커 /app/node_modules는 맵핑을 따로 안해주겠다.
- ./:/app # 로컬에 있는 모든 파일을 맵핑
ports:
- "3001:3001" # port 맵핑
stdin_open: true
defalult.conf 파일작성
server {
listen 3001; //3001번 포드 개방
location / {
root /usr/share/nginx/html; # HTML파일이 위치할 경로 설정(위에 docker 파일을 참조하면 됩니다)
index index.html index.htm; # 사이트의 index페이지로 설정 할 파일명 설정
try_files $uri $uri/ /index.html; # 리액트에서 페이지 라우팅을 제대로 하기위해 적어줘야 하는 코드
}
}
nginx는 정적파일을 제공해주기도 하므로 3001번 포트로 요청을 왔을때 해당 정적파일을 제공해줍니다.
유의 해야할점은 dockerfile, docker-compose.yml 파일, defalut.conf 파일은 최상단 파일에 위치 해야됩니다! 다 작성하셨다면 docker-compose up -d
를 커맨드라인에 입력해줍니다. (build할때 시간이 오래걸릴 수 있으므로 로컬에 있는 node_modules는 삭제 해주어도 됩니다.)
error가 발생하지 않으셨다면 docker ps 명령어를 입력하여 컨테이너가 제대로 동작하는지 확인을 합니다.
혹시 port관련 error가 발생하였다면 lsof -i tcp:3001
3001번 포트의 PID를 확인 후 kill -9 PID숫자
입력을 한 후 해당포트를 종료시켜줍니다.
그렇다면 크롬브라우저 창을 열어 localhost:3001을 입력하여 정상적으로 프로그램이 동작되는지 확인을 합니다. 저희는 따로 npm start명령어를 입력하지 않았는데도 정상적으로 프로그램이 동작 되는걸 확인 할 수 있습니다. ㅎㅎ
우선 EC2에 해당소스파일이 올라가있다고 가정하에 진행하겠습니다.
sudo apt-get install nginx
설치 후 nginx -v
버젼확인curl -s https://get.docker.com/ | sudo sh #docker 설치
sudo usermod -aG docker ubuntu // 우분투 유저 권한추가
sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
권한부여
혹시 docker ps 입력 시 Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/containers/json: dial unix /var/run/docker.sock: connect: permission denied
error가 발생하였다면,
https://stackoverflow.com/questions/48957195/how-to-fix-docker-got-permission-denied-issue 참조!
docker-compose up
을 하기전에 EC2 nginx 리버스 프록시 설정을 하도록 하겠습니다. 이것마저도 docker를 이용하여 할 수 있으나, 이번에는 직접 설정을 하도록 하겠습니다.
우선 관리자 권한으로 먼저 변경을 합니다. sudo su
이후에 vim /etc/nginx/nginx.conf
vim 편집기를 이용하여 내용을 추가합니다.(exit로 관리자권한에서 나올 수 있습니다)
내리다 보면 include /etc/nginx/sites-enabled/*;
밑에 해당 내용을 추가해줍니다. 들여쓰기 및 오타를 조심하세요.....
a,i 단축키로 내용을 적을 수 있고 내용을 다 작성하였다면 esc :wq! 로 나올 수 있습니다.
.
.
.
include /etc/nginx/sites-enabled/*;
server {
server_name 12.345.56.78; 각자 ec2 퍼블릭 IP입력 or 도메인주소
listen 80;
location / {
proxy_set_header HOST $host;
proxy_pass http://127.0.0.1:3001;
proxy_redirect off;
}
}
sudo systemctl start nginx
를 이용하여 nginx를 시작합니다. 또는
sudo systemctl restart nginx
재시작을 해줍니다. nginx가 정상적으로 동작이 되지 않을때는 sudo systemctl status nginx
입력하여 상태 및 에러가 발생하였는지 확인을 합니다.
Nov 11 16:38:23 ip-172-31-38-179 systemd[1]: Starting A high performance web server and a reverse proxy server...
Nov 11 16:38:23 ip-172-31-38-179 nginx[22900]: nginx: [emerg] unknown directive "sever_name" in /etc/nginx/nginx.conf:65
Nov 11 16:38:23 ip-172-31-38-179 nginx[22900]: nginx: configuration file /etc/nginx/nginx.conf test failed
Nov 11 16:38:23 ip-172-31-38-179 systemd[1]: nginx.service: Control process exited, code=exited status=1
Nov 11 16:38:23 ip-172-31-38-179 systemd[1]: nginx.service: Failed with result 'exit-code'.
Nov 11 16:38:23 ip-172-31-38-179 systemd[1]: Failed to start A high performance web server and a reverse proxy server.
저 같은 경우 에러가 나서 보니 65번째줄에 무언가 오타가 있었습니다.(오타조심)
다 작성을 하였다면 docker-compose up -d
커맨드를 입력 후 정상동작이 되는지 확인을 합니다. 아이피가 예를 들어 12.345.56.78이라고 가정한다면 크롬브라우저를 열어 주소창에 그대로 입력하면 됩니다.!
무중단 배포 관련 코드 수정
/etc/nginx/nginx.conf # server 스크립트 바로 위에 작성
upstream frontend {
least_conn;
server 127.0.0.1:3000 weight=5 max_fails=3 fail_timeout=10s;
server 127.0.0.1:3001 weight=10 max_fails=3 fail_timeout=10s;
}
server {
server_name 12.345.56.78; 각자 ec2 퍼블릭 IP입력 or 도메인주소
listen 80;
location / {
proxy_set_header HOST $host;
proxy_pass http://frontend;
proxy_redirect off;
}
}
docker-compose.blue.yml
version: "3"
services:
frontend: # 이름은 어떤걸로 지정해도 상관없음
build:
dockerfile: Dockerfile # dockerfile이름
context: ./ # 도커파일 위치 명시
volumes:
- /app/node_modules #도커 /app/node_modules는 맵핑을 따로 안해주겠다.
- ./:/app # 로컬에 있는 모든 파일을 맵핑
ports:
- "3000:3000" # port 맵핑
stdin_open: true
docker-compose.green.yml
version: "3"
services:
frontend: # 이름은 어떤걸로 지정해도 상관없음
build:
dockerfile: Dockerfile # dockerfile이름
context: ./ # 도커파일 위치 명시
volumes:
- /app/node_modules #도커 /app/node_modules는 맵핑을 따로 안해주겠다.
- ./:/app # 로컬에 있는 모든 파일을 맵핑
ports:
- "3001:3000" # port 맵핑
stdin_open: true
코드는 이전 docker-compose 파일과 같으나 포트번호만 다르다.
#!/bin/bash
DOCKER_APP_NAME=frontend
EXIST_BLUE=$(docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml ps | grep Up)
if [ -z "$EXIST_BLUE" ]; then
echo "blue up"
docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml up -d
sleep 10
docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yml down
else
echo "green up"
docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yml up -d
sleep 10
docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml down
fi
커맨드라인에 해당 쉘스크립드를 실행하면 서버가 downtime이 되지않고 배포가 가능해진다.
chmod +x ./deploy.sh
명령어로 deploy.sh에 실행할 수 있는 권한을 추가해 줍니다.
해당 bash shell script를 실행하는 방법은 ./delpoy.sh
or bash delpoy.sh
docker-compose에서 80번 포트를 열어주지 않았는데 어떻게 80 포트로 접근이 가능한건가요?