Skip to content

Commit f64f430

Browse files
authored
Merge pull request #17 from next-engineer/dev
Dev
2 parents 8964f6f + aedd932 commit f64f430

4 files changed

Lines changed: 100 additions & 122 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 36 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ name: Deploy to Amazon ECR & EC2
22

33
on:
44
push:
5-
branches: [ main ]
5+
branches:
6+
- main
67

78
env:
89
AWS_REGION: ap-northeast-2
@@ -15,137 +16,50 @@ env:
1516
1617
jobs:
1718
deploy:
18-
name: Build → Push(ECR) → Deploy(EC2 Private)
1919
runs-on: ubuntu-latest
2020
environment: production
2121

22-
steps:
23-
- name: Checkout
24-
uses: actions/checkout@v4
22+
steps:
23+
- uses: actions/checkout@v4
2524

26-
- name: Configure AWS credentials
27-
uses: aws-actions/configure-aws-credentials@0e613a0980cbf65ed5b322eb7a1e075d28913a83
28-
with:
29-
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
30-
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
31-
aws-region: ${{ env.AWS_REGION }}
25+
- uses: aws-actions/configure-aws-credentials@0e613a0980cbf65ed5b322eb7a1e075d28913a83
26+
with:
27+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
28+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
29+
aws-region: ${{ env.AWS_REGION }}
3230

33-
- name: Login to Amazon ECR
34-
id: login-ecr
35-
uses: aws-actions/amazon-ecr-login@62f4f872db3836360b72999f4b87f1ff13310f3a
31+
- id: login-ecr
32+
uses: aws-actions/amazon-ecr-login@62f4f872db3836360b72999f4b87f1ff13310f3a
3633

37-
- name: Build, tag, and push image to Amazon ECR
38-
id: build-image
39-
env:
40-
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
41-
IMAGE_TAG: ${{ github.sha }}
42-
run: |
43-
set -euo pipefail
44-
docker build -t "$ECR_REGISTRY/${{ env.ECR_REPOSITORY }}:$IMAGE_TAG" .
45-
docker push "$ECR_REGISTRY/${{ env.ECR_REPOSITORY }}:$IMAGE_TAG"
46-
echo "image=$ECR_REGISTRY/${{ env.ECR_REPOSITORY }}:$IMAGE_TAG" >> "$GITHUB_OUTPUT"
47-
48-
# === 여기부터 Private EC2로 배포(SSM RunCommand) ===
49-
- name: Build SSM command script
50-
id: ssm-script
51-
env:
52-
AWS_REGION: ${{ env.AWS_REGION }}
53-
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
54-
IMAGE_URI: ${{ steps.build-image.outputs.image }}
55-
CONTAINER_NAME: ${{ env.CONTAINER_NAME }}
56-
DOCKER_RUN_ARGS: ${{ env.DOCKER_RUN_ARGS }}
57-
run: |
58-
set -euo pipefail
59-
cat > deploy.sh <<'EOF'
60-
#!/usr/bin/env bash
61-
set -euo pipefail
62-
63-
echo "[1/5] ECR 로그인"
64-
aws ecr get-login-password --region "${AWS_REGION}" \
65-
| docker login --username AWS --password-stdin "${ECR_REGISTRY}"
66-
67-
echo "[2/5] 새 이미지 Pull: ${IMAGE_URI}"
68-
docker pull "${IMAGE_URI}"
69-
70-
echo "[3/5] 기존 컨테이너 정리: ${CONTAINER_NAME}"
71-
# 동일 이름 컨테이너가 있으면 중지/삭제
72-
if docker ps -a --format '{{.Names}}' | grep -wq "${CONTAINER_NAME}"; then
73-
docker rm -f "${CONTAINER_NAME}" || true
74-
fi
75-
76-
echo "[4/5] 오래된 이미지 가비지 정리(선택)"
77-
docker image prune -f || true
78-
79-
echo "[5/5] 새 컨테이너 기동"
80-
docker run -d --name "${CONTAINER_NAME}" ${DOCKER_RUN_ARGS} "${IMAGE_URI}"
81-
82-
echo "DONE"
83-
EOF
84-
85-
python3 - <<'PY' >> $GITHUB_OUTPUT
86-
import json
87-
script = open('deploy.sh','r',encoding='utf-8').read()
88-
89-
cmd = ["bash","-lc", script]
90-
print("commands=" + json.dumps(cmd))
91-
PY
34+
- id: build-image
35+
run: |
36+
IMAGE_TAG=${{ github.sha }}
37+
out=$(bash scripts/build_and_push.sh \
38+
"${{ steps.login-ecr.outputs.registry }}" \
39+
"${{ env.ECR_REPOSITORY }}" \
40+
"$IMAGE_TAG")
41+
echo "$out" >> "$GITHUB_OUTPUT"
9242
93-
- name: Send SSM RunCommand to EC2 (by InstanceIds or by Tag)
94-
id: ssm-deploy
43+
- id: ssm-deploy
9544
run: |
96-
set -euo pipefail
97-
98-
TARGETS_JSON="[]"
99-
if [ -n "${{ env.EC2_INSTANCE_IDS }}" ]; then
100-
101-
# InstanceId로 지정
102-
IFS=',' read -ra IDS <<< "${{ env.EC2_INSTANCE_IDS }}"
103-
ARR=""
104-
for id in "${IDS[@]}"; do
105-
ARR="${ARR}{\"Key\":\"InstanceIds\",\"Values\":[\"$id\"]},"
106-
done
107-
TARGETS_JSON="["${ARR%,}"]"
108-
elif [ -n "${{ env.EC2_TAG_KEY || '' }}" ] && [ -n "${{ env.EC2_TAG_VALUE || '' }}" ]; then
109-
# 태그로 지정
110-
TARGETS_JSON=$(cat <<JSON
111-
[
112-
{"Key":"tag:${{ env.EC2_TAG_KEY }}","Values":["${{ env.EC2_TAG_VALUE }}"]}
113-
]
114-
JSON
115-
)
116-
else
117-
echo "EC2 타깃(EC2_INSTANCE_IDS 또는 EC2_TAG_KEY/EC2_TAG_VALUE)을 설정하세요." >&2
118-
exit 1
119-
fi
120-
45+
IMAGE_URI=${{ steps.build-image.outputs.image }}
46+
TARGETS_JSON=$(jq -n --arg ids "${{ env.EC2_INSTANCE_IDS }}" '
47+
{Key:"InstanceIds", Values: ($ids | split(","))}
48+
' | jq -s .)
49+
50+
COMMANDS_JSON=$(jq -Rs . < scripts/deploy_container.sh)
12151
aws ssm send-command \
12252
--document-name "AWS-RunShellScript" \
123-
--comment "Pull from ECR and restart container" \
124-
--targets "${TARGETS_JSON}" \
125-
--parameters '{"commands": '${{ steps.ssm-script.outputs.commands }}'}' \
126-
--timeout-seconds 1800 \
127-
--max-concurrency "1" \
128-
--max-errors "0" \
53+
--comment "Deploy new container" \
54+
--targets "$TARGETS_JSON" \
55+
--parameters "{\"commands\":[\"bash\",\"-lc\",$COMMANDS_JSON]}" \
12956
--region "${{ env.AWS_REGION }}" \
13057
--output json > send-command.json
131-
58+
13259
COMMAND_ID=$(jq -r '.Command.CommandId' send-command.json)
133-
echo "command-id=${COMMAND_ID}" >> "$GITHUB_OUTPUT"
134-
135-
- name: Wait for SSM command to finish
136-
run: |
137-
set -euo pipefail
138-
COMMAND_ID="${{ steps.ssm-deploy.outputs.command-id }}"
139-
echo "Waiting for SSM Command $COMMAND_ID ..."
140-
# 간단 폴링
141-
for i in $(seq 1 120); do
142-
STATUS=$(aws ssm list-commands --command-id "$COMMAND_ID" --query "Commands[0].Status" --output text --region "${{ env.AWS_REGION }}")
143-
echo "SSM Status: $STATUS"
144-
case "$STATUS" in
145-
Success) exit 0 ;;
146-
Failed|Cancelled|TimedOut) echo "SSM failed: $STATUS"; exit 1 ;;
147-
esac
148-
sleep 5
149-
done
150-
echo "Timeout waiting SSM command"
151-
exit 1
60+
echo "command-id=$COMMAND_ID" >> "$GITHUB_OUTPUT"
61+
62+
- run: |
63+
bash scripts/wait_ssm.sh \
64+
"${{ env.AWS_REGION }}" \
65+
"${{ steps.ssm-deploy.outputs.command-id }}"

scripts/build_and_push.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
ECR_REGISTRY=$1
5+
ECR_REPOSITORY=$2
6+
IMAGE_TAG=$3
7+
8+
docker build -t "$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" .
9+
docker push "$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
10+
11+
echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"

scripts/deploy_container.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
AWS_REGION=$1
5+
ECR_REGISTRY=$2
6+
IMAGE_URI=$3
7+
CONTAINER_NAME=$4
8+
DOCKER_RUN_ARGS=$5
9+
10+
echo "[1/5] ECR 로그인"
11+
aws ecr get-login-password --region "$AWS_REGION" \
12+
| docker login --username AWS --password-stdin "$ECR_REGISTRY"
13+
14+
echo "[2/5] 새 이미지 Pull: $IMAGE_URI"
15+
docker pull "$IMAGE_URI"
16+
17+
echo "[3/5] 기존 컨테이너 정리: $CONTAINER_NAME"
18+
if docker ps -a --format '{{.Names}}' | grep -wq "$CONTAINER_NAME"; then
19+
docker rm -f "$CONTAINER_NAME" || true
20+
fi
21+
22+
echo "[4/5] 오래된 이미지 가비지 정리"
23+
docker image prune -f || true
24+
25+
echo "[5/5] 새 컨테이너 기동"
26+
docker run -d --name "$CONTAINER_NAME" $DOCKER_RUN_ARGS "$IMAGE_URI"
27+
28+
echo "DONE"

scripts/wait_ssm.sh

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
AWS_REGION=$1
5+
COMMAND_ID=$2
6+
7+
echo "Waiting for SSM Command $COMMAND_ID ..."
8+
9+
for i in $(seq 1 120); do
10+
STATUS=$(aws ssm list-commands \
11+
--command-id "$COMMAND_ID" \
12+
--query "Commands[0].Status" \
13+
--output text \
14+
--region "$AWS_REGION")
15+
16+
echo "SSM Status: $STATUS"
17+
case "$STATUS" in
18+
Success) exit 0 ;;
19+
Failed|Cancelled|TimedOut) echo "SSM failed: $STATUS"; exit 1 ;;
20+
esac
21+
sleep 5
22+
done
23+
24+
echo "Timeout waiting for SSM command"
25+
exit 1

0 commit comments

Comments
 (0)