-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[IDLE-518] 인프라 재구축 및 CI/CD 재가동 #258
Changes from all commits
de249a6
886cdba
60e0e78
0f2c9b7
3dd06e0
97b739b
7ba7847
05cb8f5
e7cf75a
12e3603
618c08d
0289f8f
6da3d85
2a3598b
63733f3
7626d08
acf5bec
d217dd3
4743a98
290628f
35a2c16
a112a29
008d8f5
5665589
89916cb
9ed7445
9b166a4
ad53897
4bb9094
49224d1
278b350
ffe5e36
e868544
4092ae1
edb175e
d6b15d4
1d5eff6
76742f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,6 +1,9 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
name: Production Server Deployer (CD) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
on: workflow_dispatch | ||||||||||||||||||||||||||||||||||||||||||||||||||
on: | ||||||||||||||||||||||||||||||||||||||||||||||||||
push: | ||||||||||||||||||||||||||||||||||||||||||||||||||
branches: | ||||||||||||||||||||||||||||||||||||||||||||||||||
- main | ||||||||||||||||||||||||||||||||||||||||||||||||||
jobs: | ||||||||||||||||||||||||||||||||||||||||||||||||||
deploy: | ||||||||||||||||||||||||||||||||||||||||||||||||||
runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -50,7 +53,13 @@ jobs: | |||||||||||||||||||||||||||||||||||||||||||||||||
username: ${{ vars.BASTION_USERNAME }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
key: ${{ secrets.INSTANCE_PEM_KEY }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
script: | | ||||||||||||||||||||||||||||||||||||||||||||||||||
ssh -o "ProxyJump=${{ vars.BASTION_HOST }}" -i ${{ secrets.INSTANCE_PEM_KEY }} ${{ vars.INSTANCE_USERNAME }}@${{ vars.INSTANCE_HOST }} << 'EOF' | ||||||||||||||||||||||||||||||||||||||||||||||||||
if [ ! -f private_key.pem ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
echo "${{ secrets.INSTANCE_PEM_KEY }}" > private_key.pem | ||||||||||||||||||||||||||||||||||||||||||||||||||
chmod 600 private_key.pem | ||||||||||||||||||||||||||||||||||||||||||||||||||
fi | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+56
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PEM 키 파일 관리 방식 개선이 필요합니다. 여러 단계에서 PEM 키 파일이 반복적으로 생성되고 있으며, 보안 위험이 있습니다. 다음과 같이 PEM 키 관리를 개선하는 것을 권장드립니다:
- name: Setup SSH Key
id: ssh-key
run: |
SSH_KEY_PATH="${RUNNER_TEMP}/private_key.pem"
echo "${{ secrets.INSTANCE_PEM_KEY }}" > "${SSH_KEY_PATH}"
chmod 600 "${SSH_KEY_PATH}"
echo "key_path=${SSH_KEY_PATH}" >> $GITHUB_OUTPUT
- if [ ! -f private_key.pem ]; then
- echo "${{ secrets.INSTANCE_PEM_KEY }}" > private_key.pem
- chmod 600 private_key.pem
- fi
+ SSH_KEY_PATH="${{ steps.ssh-key.outputs.key_path }}"
- name: Cleanup SSH Key
if: always()
run: rm -f ${{ steps.ssh-key.outputs.key_path }} Also applies to: 88-91, 122-124 |
||||||||||||||||||||||||||||||||||||||||||||||||||
ssh -f -N -M -S my-cicd-socket -o StrictHostKeyChecking=no -i private_key.pem -L 2222:${{ vars.INSTANCE_HOST }}:22 ec2-user@${{ vars.BASTION_HOST }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
ssh -o StrictHostKeyChecking=no -i private_key.pem -p 2222 ubuntu@localhost << 'EOF' | ||||||||||||||||||||||||||||||||||||||||||||||||||
echo "Connected to Private Subnet productionServer via SSH Tunneling" | ||||||||||||||||||||||||||||||||||||||||||||||||||
if ! command -v docker >/dev/null 2>&1; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
echo "Installing Docker..." | ||||||||||||||||||||||||||||||||||||||||||||||||||
sudo apt-get update | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -66,23 +75,42 @@ jobs: | |||||||||||||||||||||||||||||||||||||||||||||||||
echo "Docker Compose already installed." | ||||||||||||||||||||||||||||||||||||||||||||||||||
fi | ||||||||||||||||||||||||||||||||||||||||||||||||||
EOF | ||||||||||||||||||||||||||||||||||||||||||||||||||
ssh -S my-cicd-socket -O exit ec2-user@${{ vars.BASTION_HOST }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
rm -f private_key.pem | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
- name: Configuration Env file | ||||||||||||||||||||||||||||||||||||||||||||||||||
uses: appleboy/ssh-action@master | ||||||||||||||||||||||||||||||||||||||||||||||||||
env: | ||||||||||||||||||||||||||||||||||||||||||||||||||
VARS_CONTEXT: ${{ toJson(vars) }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
SECRETS_CONTEXT: ${{ toJson(secrets) }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
with: | ||||||||||||||||||||||||||||||||||||||||||||||||||
host: ${{ vars.BASTION_HOST }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
username: ${{ vars.BASTION_USERNAME }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
key: ${{ secrets.INSTANCE_PEM_KEY }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
envs: VARS_CONTEXT,SECRETS_CONTEXT | ||||||||||||||||||||||||||||||||||||||||||||||||||
script: | | ||||||||||||||||||||||||||||||||||||||||||||||||||
ssh -o "ProxyJump=${{ vars.BASTION_HOST }}" -i ${{ secrets.INSTANCE_PEM_KEY }} ${{ vars.INSTANCE_USERNAME }}@${{ vars.INSTANCE_HOST }} << 'EOF' | ||||||||||||||||||||||||||||||||||||||||||||||||||
cd ~/app/docker | ||||||||||||||||||||||||||||||||||||||||||||||||||
jq -s '.[0] * .[1] | del(.INSTANCE_PEM_KEY)' <(echo "$VARS_CONTEXT") <(echo "$SECRETS_CONTEXT") \ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| jq -r 'to_entries | map("\(.key)=\(.value)") | .[]' > .env | ||||||||||||||||||||||||||||||||||||||||||||||||||
if [ ! -f private_key.pem ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
echo "${{ secrets.INSTANCE_PEM_KEY }}" > private_key.pem | ||||||||||||||||||||||||||||||||||||||||||||||||||
chmod 600 private_key.pem | ||||||||||||||||||||||||||||||||||||||||||||||||||
fi | ||||||||||||||||||||||||||||||||||||||||||||||||||
ssh -f -N -M -S my-cicd-socket -o StrictHostKeyChecking=no -i private_key.pem -L 2222:${{ vars.INSTANCE_HOST }}:22 ec2-user@${{ vars.BASTION_HOST }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
ssh -o StrictHostKeyChecking=no -i private_key.pem -p 2222 ubuntu@localhost << 'EOF' | ||||||||||||||||||||||||||||||||||||||||||||||||||
echo "Connected to Private Subnet productionServer via SSH Tunneling" | ||||||||||||||||||||||||||||||||||||||||||||||||||
cd ~/app/docker | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
echo "VARS_CONTEXT: ${{ toJson(vars) }}" | ||||||||||||||||||||||||||||||||||||||||||||||||||
echo "SECRETS_CONTEXT: ${{ toJson(secrets) }}" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
VARS_CONTEXT_JSON='${{ toJson(vars) }}' | ||||||||||||||||||||||||||||||||||||||||||||||||||
SECRETS_CONTEXT_JSON='${{ toJson(secrets) }}' | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
echo "$VARS_CONTEXT_JSON" > vars_context.json | ||||||||||||||||||||||||||||||||||||||||||||||||||
echo "$SECRETS_CONTEXT_JSON" > secrets_context.json | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
jq -s '.[0] * .[1]' vars_context.json secrets_context.json \ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| jq -r 'to_entries | map(select(.key != "INSTANCE_PEM_KEY")) | map("\(.key)=\(.value)") | .[]' > .env | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
echo ".env file generated:" | ||||||||||||||||||||||||||||||||||||||||||||||||||
cat .env | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+97
to
+110
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 환경 변수 로깅 보안 위험이 있습니다. 환경 변수 컨텍스트를 echo로 출력하는 것은 보안상 위험합니다. 다음과 같이 디버그 로깅을 제거하고 안전한 방식으로 변경하는 것을 권장드립니다: - echo "VARS_CONTEXT: ${{ toJson(vars) }}"
- echo "SECRETS_CONTEXT: ${{ toJson(secrets) }}"
- echo ".env file generated:"
- cat .env
+ echo "환경 파일이 성공적으로 생성되었습니다." 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||
EOF | ||||||||||||||||||||||||||||||||||||||||||||||||||
ssh -S my-cicd-socket -O exit ec2-user@${{ vars.BASTION_HOST }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
rm -f private_key.pem | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
- name: SSH to Bastion and deploy to Production server | ||||||||||||||||||||||||||||||||||||||||||||||||||
uses: appleboy/ssh-action@master | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -91,17 +119,25 @@ jobs: | |||||||||||||||||||||||||||||||||||||||||||||||||
username: ${{ vars.BASTION_USERNAME }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
key: ${{ secrets.INSTANCE_PEM_KEY }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
script: | | ||||||||||||||||||||||||||||||||||||||||||||||||||
ssh -o "ProxyJump=${{ vars.BASTION_HOST }}" -i ${{ secrets.INSTANCE_PEM_KEY }} ${{ vars.INSTANCE_USERNAME }}@${{ vars.INSTANCE_HOST }} << 'EOF' | ||||||||||||||||||||||||||||||||||||||||||||||||||
sudo docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
sudo docker pull public.ecr.aws/f5q3r6m5/caremeet:latest | ||||||||||||||||||||||||||||||||||||||||||||||||||
if [ $(sudo docker ps -q -f name=caremeet_server_prod) ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
sudo docker stop caremeet_server_prod | ||||||||||||||||||||||||||||||||||||||||||||||||||
sudo docker rm caremeet_server_prod | ||||||||||||||||||||||||||||||||||||||||||||||||||
if [ ! -f private_key.pem ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
echo "${{ secrets.INSTANCE_PEM_KEY }}" > private_key.pem | ||||||||||||||||||||||||||||||||||||||||||||||||||
chmod 600 private_key.pem | ||||||||||||||||||||||||||||||||||||||||||||||||||
fi | ||||||||||||||||||||||||||||||||||||||||||||||||||
sudo docker run --name caremeet_server_prod --env-file ./app/docker/.env \ | ||||||||||||||||||||||||||||||||||||||||||||||||||
-e SPRING_PROFILES_ACTIVE=prod \ | ||||||||||||||||||||||||||||||||||||||||||||||||||
-d -p 8080:8080 public.ecr.aws/f5q3r6m5/caremeet:latest | ||||||||||||||||||||||||||||||||||||||||||||||||||
ssh -f -N -M -S my-cicd-socket -o StrictHostKeyChecking=no -i private_key.pem -L 2222:${{ vars.INSTANCE_HOST }}:22 ec2-user@${{ vars.BASTION_HOST }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
ssh -o StrictHostKeyChecking=no -i private_key.pem -p 2222 ubuntu@localhost << 'EOF' | ||||||||||||||||||||||||||||||||||||||||||||||||||
echo "Connected to Private Subnet productionServer via SSH Tunneling" | ||||||||||||||||||||||||||||||||||||||||||||||||||
sudo docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
sudo docker pull public.ecr.aws/e4z1s9l7/caremeet:latest | ||||||||||||||||||||||||||||||||||||||||||||||||||
if [ $(sudo docker ps -q -f name=caremeet_server_prod) ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||
sudo docker stop caremeet_server_prod | ||||||||||||||||||||||||||||||||||||||||||||||||||
sudo docker rm caremeet_server_prod | ||||||||||||||||||||||||||||||||||||||||||||||||||
fi | ||||||||||||||||||||||||||||||||||||||||||||||||||
sudo docker run --name caremeet_server_prod --env-file ./app/docker/.env \ | ||||||||||||||||||||||||||||||||||||||||||||||||||
-e SPRING_PROFILES_ACTIVE=prod \ | ||||||||||||||||||||||||||||||||||||||||||||||||||
-d -p 8080:8080 public.ecr.aws/e4z1s9l7/caremeet:latest | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+129
to
+137
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 배포 프로세스 개선이 필요합니다. 현재 배포 프로세스에는 몇 가지 개선이 필요한 부분이 있습니다. 다음과 같은 개선사항을 제안드립니다:
- sudo docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
+ echo "${{ secrets.DOCKER_CONFIG_JSON }}" > ${HOME}/.docker/config.json
+ sudo docker login
sudo docker run --name caremeet_server_prod --env-file ./app/docker/.env \
-e SPRING_PROFILES_ACTIVE=prod \
-d -p 8080:8080 public.ecr.aws/e4z1s9l7/caremeet:latest
+ echo "서버 헬스체크 시작..."
+ for i in {1..30}; do
+ if curl -s http://localhost:8080/actuator/health | grep -q "UP"; then
+ echo "서버가 정상적으로 시작되었습니다."
+ exit 0
+ fi
+ echo "헬스체크 재시도 중... ($i/30)"
+ sleep 10
+ done
+ echo "서버 시작 실패"
+ exit 1
+ # 이전 이미지 태그 저장
+ PREVIOUS_IMAGE=$(sudo docker inspect caremeet_server_prod --format='{{.Config.Image}}')
+
+ # 배포 실패시 롤백
+ if [ $? -ne 0 ]; then
+ echo "배포 실패. 이전 버전으로 롤백 중..."
+ sudo docker run --name caremeet_server_prod --env-file ./app/docker/.env \
+ -e SPRING_PROFILES_ACTIVE=prod \
+ -d -p 8080:8080 ${PREVIOUS_IMAGE}
+ fi
|
||||||||||||||||||||||||||||||||||||||||||||||||||
EOF | ||||||||||||||||||||||||||||||||||||||||||||||||||
ssh -S my-cicd-socket -O exit ec2-user@${{ vars.BASTION_HOST }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
rm -f private_key.pem | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
- name: Remove GitHub Actions IP | ||||||||||||||||||||||||||||||||||||||||||||||||||
run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,17 @@ | ||
|
||
spring: | ||
datasource: | ||
driver-class-name: com.mysql.cj.jdbc.Driver | ||
url: ${DB_URL:jdbc:mysql://localhost:3306/idle?serverTimezone=Asia/Seoul&characterEncoding=UTF-8} | ||
url: ${DB_URL:jdbc:mysql://localhost:3306/caremeet?serverTimezone=Asia/Seoul&characterEncoding=UTF-8} | ||
username: ${DB_USERNAME:root} | ||
password: ${DB_PASSWORD:mysql} | ||
jpa: | ||
Comment on lines
+5
to
8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 데이터베이스 자격 증명 보안 강화 필요 민감한 데이터베이스 접속 정보가 기본값으로 설정되어 있습니다. 보안 강화를 위해 다음 사항을 고려해주세요:
|
||
open-in-view: false | ||
properties: | ||
hibernate.format_sql: true | ||
dialect: org.hibernate.dialect.MySQLDialect | ||
hibernate: | ||
ddl-auto: validate | ||
data: | ||
redis: | ||
host: ${REDIS_HOST:localhost} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,19 +10,26 @@ services: | |
pull_policy: always | ||
env_file: | ||
- .env | ||
depends_on: | ||
- mysql | ||
ports: | ||
- "8080:8080" | ||
depends_on: | ||
- mysql | ||
- redis | ||
networks: | ||
- redis-caremeet-net | ||
- mysql-caremeet-net | ||
|
||
mysql: | ||
image: mysql:8.0.33 | ||
container_name: mysql_dev | ||
environment: | ||
MYSQL_DATABASE: idle | ||
MYSQL_DATABASE: caremeet | ||
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} | ||
TZ: Asia/Seoul | ||
ports: | ||
- "3306:3306" | ||
networks: | ||
- mysql-caremeet-net | ||
Comment on lines
+24
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion MySQL 컨테이너 보안 강화 필요 MySQL 설정에 대한 보안 개선사항:
다음과 같이 수정을 제안합니다: mysql:
image: mysql:8.0.33
container_name: mysql_dev
+ user: "999:999"
environment:
- MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
+ MYSQL_RANDOM_ROOT_PASSWORD: "yes"
+ MYSQL_USER: ${DB_USER}
+ MYSQL_PASSWORD_FILE: /run/secrets/db_password
volumes:
+ - type: volume
+ source: mysql-volume
+ target: /var/lib/mysql
+ volume:
+ nocopy: true
|
||
|
||
redis: | ||
image: redis:7.2.5 | ||
|
@@ -35,6 +42,14 @@ services: | |
volumes: | ||
- redis-volume:/data | ||
restart: unless-stopped | ||
networks: | ||
- redis-caremeet-net | ||
|
||
networks: | ||
mysql-caremeet-net: | ||
driver: bridge | ||
redis-caremeet-net: | ||
driver: bridge | ||
|
||
volumes: | ||
mysql-volume: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
자동 배포 트리거에 대한 보호 장치가 필요합니다.
main 브랜치 푸시 시 자동 배포되는 설정은 위험할 수 있습니다.
다음과 같은 보호 장치 추가를 권장드립니다:
📝 Committable suggestion