컴공생의 발자취

EC2 분리하기: Front / Back / PostgreSQL / MongoDB / redis 본문

🧡 AWS

EC2 분리하기: Front / Back / PostgreSQL / MongoDB / redis

MNY 2024. 10. 23. 18:15
728x90
반응형
Keyword
  1. 서브 도메인
  2. docker-compose restart
  3. docker network
  4. docker exec -it
  5. psql
  6. mongosh
  7. redis

 

 EC2 생성하기(공통)

EC2 인스턴스 생성

보안그룹:

  • 기존의 보안 그룹에서 추가
  • 프론트: 3000(그냥 나는 3000으로 하고 싶었음)
  • 백엔드: 8080(기존 보안 그룹에 존재)
  • DB - PostgreSQL : 5432
  • MongoDB : 27017
  • Redis : 6379

 

EC2 인스턴스 초기 세팅

시스템 업데이트 및 업그레이드:

sudo apt update -y
sudo apt upgrade -y

 

Docker 및 Docker Compose 설치:

  • Docker 설치
sudo apt install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER
  • Docker Compose 설치
sudo apt install -y curl
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
  • Docker 및 Docker Compose 설치 확인
docker --version
docker-compose --version
  • EC2 재시작

서브 도메인에 생성한 EC2 연결

서브 도메인에 생성한 EC2의 private IP 연결

 

 프론트 분리하기 

프론트 Jenkins Script 업데이트

pipeline {
    agent any

    environment {
		    // GitHub credentials
        GIT_CREDENTIALS_ID = 'github-token'
        GIT_URL = 'https://github.com/today-space/today-space-front.git'
        GIT_BRANCH = 'release'
        
        // EC2
        SSH_CREDENTIALS_ID = 'ec2-ssh-key'
        EC2_USER = 'ubuntu'
        EC2_DOMAIN = 'front.today-space.com'
       
        // Docker Hub credentials
        DOCKER_HUB_CREDENTIALS = 'docker-hub-credentials'
        DOCKER_HUB_REPO = 'ysy561356/today-space-front'
        DOCKER_CONTAINER = 'front-today-space-container'
        DOCKER_IMAGE_TAG = 'latest'
        
        REACT_APP_API_URL='https://today-space.com'
        
        REACT_APP_KAKAO_AUTH_URL='https://kauth.kakao.com/oauth/authorize'
        REACT_APP_KAKAO_REST_API_KEY='6cd61cbdb917a1046bf437980b1e2ac9'
        REACT_APP_KAKAO_REDIRECT_URL='https://today-space.com/oauth/kakao'
        
        REACT_APP_NAVER_AUTH_URL='https://nid.naver.com/oauth2.0/authorize'
        REACT_APP_NAVER_REST_API_KEY='mgvICujU1zvQrtz_IQOA'
        REACT_APP_NAVER_REDIRECT_URL='https://today-space.com/oauth/naver'
        REACT_APP_NAVER_STATE='reactNaverSocialState'
        
        REACT_APP_GOOGLE_AUTH_URL='https://accounts.google.com/o/oauth2/v2/auth'
        REACT_APP_GOOGLE_REST_API_KEY='878062679505-oh34mk7fm5mpipprk9o139i8if40b3qf.apps.googleusercontent.com'
        REACT_APP_GOOGLE_REDIRECT_URL='https://today-space.com/oauth/google'
    }

    stages {
        stage('Clone Repository') {
            steps {
                script {
                    // GitHub 저장소에서 코드 클론
                    git credentialsId: "${GIT_CREDENTIALS_ID}", branch: "${GIT_BRANCH}", url: "${GIT_URL}"
                }
            }
        }
        stage('Prepare .env') {
            steps {
                script {
                    sh """
                    touch .env
                    echo REACT_APP_API_URL=${REACT_APP_API_URL} >> .env
                    echo REACT_APP_KAKAO_AUTH_URL=${REACT_APP_KAKAO_AUTH_URL} >> .env
                    echo REACT_APP_KAKAO_REST_API_KEY=${REACT_APP_KAKAO_REST_API_KEY} >> .env
                    echo REACT_APP_KAKAO_REDIRECT_URL=${REACT_APP_KAKAO_REDIRECT_URL} >> .env
                    echo REACT_APP_NAVER_AUTH_URL=${REACT_APP_NAVER_AUTH_URL} >> .env
                    echo REACT_APP_NAVER_REST_API_KEY=${REACT_APP_NAVER_REST_API_KEY} >> .env
                    echo REACT_APP_NAVER_REDIRECT_URL=${REACT_APP_NAVER_REDIRECT_URL} >> .env
                    echo REACT_APP_NAVER_STATE=${REACT_APP_NAVER_STATE} >> .env
                    echo REACT_APP_GOOGLE_AUTH_URL=${REACT_APP_GOOGLE_AUTH_URL} >> .env
                    echo REACT_APP_GOOGLE_REST_API_KEY=${REACT_APP_GOOGLE_REST_API_KEY} >> .env
                    echo REACT_APP_GOOGLE_REDIRECT_URL=${REACT_APP_GOOGLE_REDIRECT_URL} >> .env
                    """
                }
            }
        }
        stage('Build') {
            steps {
                script {
                    // Docker 이미지 생성
                    sh 'docker build -t ${DOCKER_HUB_REPO}:${DOCKER_IMAGE_TAG} .'
                }
            }
        }
        stage('Push Docker Image to Docker Hub') {
            steps {
                script {
                    // Docker Hub에 로그인
                    withCredentials([usernamePassword(credentialsId: DOCKER_HUB_CREDENTIALS, usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
                        sh 'echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin'
                    }

                    // Docker 이미지 push
                        sh "docker push ${DOCKER_HUB_REPO}:${DOCKER_IMAGE_TAG}"
                }
            }
        }
        stage('Deploy') {
            steps {
                script {
                    withCredentials([sshUserPrivateKey(credentialsId: "${SSH_CREDENTIALS_ID}", keyFileVariable: 'SSH_KEY')]) {
                        def sshKey = env.SSH_KEY
                        
                        // 권한 변경
                        sh 'chmod 400 ' + sshKey
                        
                        // docker container down
                        sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker stop ${DOCKER_CONTAINER}"'
                        
                        // docker container remove
                        sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker rm ${DOCKER_CONTAINER}"'
           
                        // docker image pull
                        sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker pull ${DOCKER_HUB_REPO}:${DOCKER_IMAGE_TAG}"' // 이미지 명시

                        // 새로운 docker-compose 시작
                        sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker-compose up -d"'

                    }
                }
            }
        }
    }
    post {
        always {
            cleanWs()
        }
        success {
            echo 'Deployment successful!'
        }
        failure {
            echo 'Deployment failed!'
        }
    }
}

 

docker-compose 업데이트 및 생성

처음 만들었던 EC2(back + front + nginx + certbot)에서 수정

version: '3.8'

services:
  back:
    image: today-space-back:latest
    container_name: today-space-back
    env_file:
	    - ./config/.env
    ports:
      - "8080:8080"
    depends_on:
      - db

  db:
    image: postgres:14
    container_name: today-space-db
    env_file:
	    - ./config/.env
    volumes:
      - db_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
      
  nginx:
		image: nginx:latest
    container_name: today-space-nginx
	  ports:
		  - "80:80"
		  - "443:443"
	  volumes:
		  - ./data/nginx/app.conf:/etc/nginx/conf.d/default.conf
		  - ./data/certbot/conf:/etc/letsencrypt 
      - ./data/certbot/www:/var/www/certbot
	  depends_on:
		  - back

	certbot:
    image: certbot/certbot
    restart: unless-stopped
    volumes:
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

volumes:
  db_data:

 

새로 만든 front EC2에서 docker-compose.yml 생성

version: '3.8'

services:
  nginx:
    image: ysy561356/today-space-front:latest
    restart: unless-stopped
    container_name: front-today-space-container
    ports:
      - "3000:3000"
    volumes:
      - ./data/nginx/app.conf:/etc/nginx/conf.d/default.conf

volumes:
  db_data:

 

app.conf(nginx.conf) 업데이트 및 생성

처음 만들었던 EC2(back + front + nginx + certbot)에서 수정

server {
    listen 80;
    server_name today-space.com;
    server_tokens off;

    location /.well-known/acme-challenge/ {
        allow all;
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name today-space.com;
    server_tokens off;

    ssl_certificate /etc/letsencrypt/live/today-space.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/today-space.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
        proxy_pass http://front.today-space.com;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        #root /usr/share/nginx/html;
        #try_files $uri /index.html;
        #index index.html index.htm;
    }

    location /v1 {
        proxy_pass http://today-space.com:8080; # 혹은 다른 내부 네트워크 서비스로 설정
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    error_page 500 502 503 504   /50x.html;
    location = /50x.html {
    root /usr/share/nginx/html;
    }

}

 

새로 만든 front EC2에서 ./data/nginx/app.conf 생성

server {
    listen 3000;
    server_name front.today-space.com;
    server_tokens off;

    location / {
        root /usr/share/nginx/html;
        try_files $uri /index.html;
        index index.html;
    }
}

 

 백엔드 분리하기 

백엔드 Jenkins Script 업데이트

pipeline {
    agent any

    environment {
        // Docker Hub credentials
        DOCKER_HUB_CREDENTIALS = 'docker-hub-credentials'
        DOCKER_HUB_REPO = 'ysy561356/today-space-back'
        DOCKER_CONTAINER = 'back-today-space-container'
        
        // Github credentials
        GIT_CREDENTIALS_ID = 'github-token'
        GIT_BRANCH = 'release'
        GIT_URL = 'https://github.com/today-space/today-space-back.git'
        
        // EC2
        SSH_CREDENTIALS_ID = 'ec2-ssh-key'
        EC2_USER = 'ubuntu'
        EC2_DOMAIN = 'back.today-space.com'
        DOCKER_IMAGE_TAG = 'latest'
        
        // DB
        DB_URL = 'jdbc:postgresql://postgresql.today-space.com:5432/space'
        DB_USERNAME = 'youngju'
        DB_PASSWORD = '4564'
        
        // JWT
        JWT_SECRET_KEY = '7Iqk7YyM66W07YOA7L2U65Sp7YG065+9c3ByaW5n7Ius7ZmU7KO87LCo7JWE7JuD7IaM7Iux7ZSE66Gc7KCd7Yq47YyM7J2067iM66CI7KCE65Oc7YyAand0c2VjcmV0a2V5'
        JWT_ACCESS_TOKEN_EXPIRATION = 1800000
        JWT_REFRESH_TOKEN_EXPIRATION = 1209600000
        
        // S3
        BUCKET_NAME = 'today-space'
        ACCESS_KEY_ID = 'AKIATCKAMVLZ5NQSKIEX'
        SECRET_ACCESS_KEY = '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'
        
        // Social Login
        KAKAO_REST_API_KEY = '6cd61cbdb917a1046bf437980b1e2ac9'
        NAVER_REST_API_KEY = 'mgvICujU1zvQrtz_IQOA'
        NAVER_REST_API_SECRET_KEY = 'drUb2lRtGb'
        GOOGLE_REST_API_KEY = '878062679505-oh34mk7fm5mpipprk9o139i8if40b3qf.apps.googleusercontent.com'
        GOOGLE_REST_API_SECRET_KEY = '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'
    }

    stages {
        stage('Clone Git Repository') {
            steps {
                script {
                    // GitHub 저장소에서 코드 클론
                    git credentialsId: "${GIT_CREDENTIALS_ID}", branch: "${GIT_BRANCH}", url: "${GIT_URL}"
                    
                    // gradlew 파일에 실행 권한 부여
                    sh 'chmod +x gradlew'
                    
                    // Gradle 빌드
                    sh './gradlew build'
                    
                    // destination 디렉토리 생성
                    sh 'mkdir -p ../destination'
                    sh 'mkdir -p ../destination/build/libs'
                    
                    // JAR 파일과 Dockerfile을 특정 경로로 이동
                    sh 'cp build/libs/*.jar ../destination/build/libs'
                    sh 'cp Dockerfile ../destination/'
                }
            }
        }
        stage('Prepare .env') {
            steps {
                script {
                    sh '''
                    touch ../destination/back.env
                    echo DB_URL=$DB_URL >> ../destination/back.env
                    echo DB_USERNAME=$DB_USERNAME >> ../destination/back.env
                    echo DB_PASSWORD=$DB_PASSWORD >> ../destination/back.env
                    echo JWT_SECRET_KEY=$JWT_SECRET_KEY >> ../destination/back.env
                    echo JWT_ACCESS_TOKEN_EXPIRATION=$JWT_ACCESS_TOKEN_EXPIRATION >> ../destination/back.env
                    echo JWT_REFRESH_TOKEN_EXPIRATION=$JWT_REFRESH_TOKEN_EXPIRATION >> ../destination/back.env
                    echo BUCKET_NAME=$BUCKET_NAME >> ../destination/back.env
                    echo ACCESS_KEY_ID=$ACCESS_KEY_ID >> ../destination/back.env
                    echo SECRET_ACCESS_KEY=$SECRET_ACCESS_KEY >> ../destination/back.env
                    echo KAKAO_REST_API_KEY=$KAKAO_REST_API_KEY >> ../destination/back.env
                    echo NAVER_REST_API_KEY=$NAVER_REST_API_KEY >> ../destination/back.env
                    echo NAVER_REST_API_SECRET_KEY=$NAVER_REST_API_SECRET_KEY >> ../destination/back.env
                    echo GOOGLE_REST_API_KEY=$GOOGLE_REST_API_KEY >> ../destination/back.env
                    echo GOOGLE_REST_API_SECRET_KEY=$GOOGLE_REST_API_SECRET_KEY >> ../destination/back.env
                    '''
                }
            }
        }
        stage('Build and Push Docker Image') {
		        steps {
		            script {
		                dir('../destination') { // 특정 경로로 이동
				                // Git 태그를 이용해 버전 설정
				                def gitTag = sh(returnStdout: true, script: 'git describe --tags --always').trim()
				                def dockerImage = docker.build("${DOCKER_HUB_REPO}:${gitTag}", "./")
		                  
				                
		                    // Docker Hub에 로그인
		                    withCredentials([usernamePassword(credentialsId: DOCKER_HUB_CREDENTIALS, usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
		                        sh 'echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin'
		                    }
		                    
		                    // docker 이미지 태그별 push
		                    dockerImage.push("${gitTag}")
		                    dockerImage.push("latest")		                }
		            }
		        }
		    }
        stage('Deploy') {
            steps {
                script {
                    withCredentials([sshUserPrivateKey(credentialsId: "${SSH_CREDENTIALS_ID}", keyFileVariable: 'SSH_KEY')]) {
                        def sshKey = env.SSH_KEY
                        
                        // 권한 변경
                        sh 'chmod 400 ' + sshKey
                        
                        // docker container down
                        sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker stop ${DOCKER_CONTAINER}"'
                        
                        // docker container remove
                        sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker rm ${DOCKER_CONTAINER}"'
           
                        // docker image pull
                        sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker pull ${DOCKER_HUB_REPO}:${DOCKER_IMAGE_TAG}"' // 이미지 명시

                        // 새로운 docker-compose 시작
                        sh 'ssh -v -o StrictHostKeyChecking=no -i ' + sshKey + ' ${EC2_USER}@${EC2_DOMAIN} "docker-compose up -d"'

                    }
                }
            }
        }
    }
    post {
        always {
            cleanWs()
        }
        success {
            echo 'Deployment successful!'
        }
        failure {
            echo 'Deployment failed!'
        }
    }
}

 

docker-compose 업데이트 및 생성

처음 만들었던 EC2(back + front + nginx + certbot)에서 수정

version: '3.8'

services:
  nginx:
		image: nginx:latest
    container_name: today-space-nginx
	  ports:
		  - "80:80"
		  - "443:443"
	  volumes:
		  - ./data/nginx/app.conf:/etc/nginx/conf.d/default.conf
		  - ./data/certbot/conf:/etc/letsencrypt 
      - ./data/certbot/www:/var/www/certbot
	  depends_on:

	certbot:
    image: certbot/certbot
    restart: unless-stopped
    volumes:
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

volumes:
  db_data:

 

새로 만든 back EC2에서 docker-compose.yml 생성

version: '3.8'

services:
  nginx:
    image: ysy561356/today-space-back:latest
    restart: unless-stopped
    container_name: back-today-space-container
    env_file: ./config/back.env
    ports:
      - "8080:8080"

volumes:
  db_data:

 

환경변수 파일 만들기

config 디렉토리 생성

  • 젠킨스에서 만든 환경변수 파일을 위치시킬 디렉토리 생성
  • 동작 확인을 위해서는 back.env 파일 직접 EC2에서 만들어서 실행시켜보기

 

 DB 분리하기 

docker-compose.yml 생성

version: '3.8'

services:
  db:
    image: postgres:14
    container_name: postgres-today-space-container
    env_file: ./config/postgres.env
    volumes:
      - ./db_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  db_data:

환경변수 파일 만들기

config 디렉토리 생성 및 이동

postgres.env 파일 생성 및 작성:

POSTGRES_DB=space
POSTGRES_USER=youngju
POSTGRES_PASSWORD=4564

 

 MongoDB 추가하기 

docker-compose.yml 생성

version: '3.8'

services:
  mongo:
    image: mongo:latest
    restart: unless-stopped
    container_name: mongo-today-space-container
    env_file: ./config/mongo.env
    ports:
      - "27017:27017"

volumes:
  db_data:

환경변수 파일 만들기

config 디렉토리 생성 및 이동

postgres.env 파일 생성 및 작성:

MONGO_INITDB_ROOT_USERNAME=root
MONGO_INITDB_ROOT_PASSWORD=todayspace4321!

back - Jenkins 환경변수 추가

// enviroment
MONGO_DB_URI = 'mongodb://root:todayspace4321!@mongo.today-space.com:27017/today_space?authSource=admin&authMechanism=SCRAM-SHA-1'
// mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=writeapp&w=1; 

// Prepare .env
echo MONGO_DB_URI=$MONGO_DB_URI >> ../destination/back.env

 

컬렉션 추가하기

mongosh 들어가기:

docker exec -it [mongodb 컨테이너명] mongosh

// ex: docker exec -it mongo-today-space-container mongosh

 

admin으로 변경:

use admin

 

유저 추가:

db.auth(”root”, “todayspace4321!”)

 

컬렉션 추가:

db.createCollection("myNewCollection")
db.myNewCollection.insertOne({ name: "example", value: 123 })
// 값을 하나 추가해야 컬렉션 생성을 확인할 수 있음

 

 Redis 추가하기 

docker-compose.yml 생성

version: '3.8'

services:
  redis:
    image: redis
    container_name: redis-today_space_container
    ports:
      - "6379:6379"
    command: redis-server --requirepass todayspace4321!
    restart: unless-stopped

volumes:
  db_data:

back - Jenkins 환경변수 추가

// enviroment
REDIS_DB_URL = 'redis://default:todayspace4321!@redis.todayspace.com:6379'

// Prepare .env
echo REDIS_DB_URL=$REDIS_DB_URL >> ../destination/back.env

 

 참고 자료 

  • docker network
 

[Docker] Docker 컨테이너 네트워크

Docker 컨테이너끼리 통신할 때는 Docker Network를 통해 수행하고 'docker network ls' 명령으로 Docker 네트워크 목록을 확인할 수 있다.기본적으로 bridge, host, none 네트워크가 있다.docker network ls \[옵

velog.io

 

 

 

 

728x90
반응형