name: CD Workflow - Build & Push to ECRon: push: branches: [ "release" ] jobs: # ---------------------------------------------------------------- # JOB 1: Docker 이미지를 빌드하고 ECR에 푸시 # ---------------------------------------------------------------- build-and-push: runs-on: ubuntu-latest # give GITHUB_TOKEN to be able to read ONLY permissions: contents: read # `outputs` block is used to **pass data from one job to another job** within the same workflow outputs: # repo_uri: ${{ steps.prep.outputs.repo_uri }} image_tag: ${{ steps.prep.outputs.image_tag }} steps: # 소스 체크아웃 - name: Checkout uses: actions/checkout@v3 # AWS 자격 증명 설정 (secrets 사용) - name: AWS CLI 설정 uses: aws-actions/configure-aws-credentials@v2 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-east-1 # ECR 로그인 (계정 ID를 Secret에서 참조) - name: Login to Amazon ECR Public id: login-ecr-public uses: aws-actions/amazon-ecr-login@v2 with: registry-type: public # (선택) 이미지 태그 구성 - 커밋 해시 7자리 +latest - name: Prepare tags id: prep run: | echo "IMAGE_TAG=${GITHUB_SHA::7}" >> $GITHUB_ENV echo "REPO_URI=${{ secrets.ECR_REPOSITORY_URI }}" >> $GITHUB_ENV echo "IMAGE_TAG=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT # Docker 빌드 (dockerfile 사용) - name: Docker build run: | docker build -t "$REPO_URI:$IMAGE_TAG" -t "$REPO_URI:latest" . # ECR 푸쉬 - name: Docker push run: | docker push "$REPO_URI:$IMAGE_TAG" docker push "$REPO_URI:latest" # ---------------------------------------------------------------- # JOB 2: 새 이미지를 ECS 서비스에 배포 # ---------------------------------------------------------------- deploy-to-ecs: ...
permissions: contents: read
grants the job read-only permission to your repository’s contents
The actions/checkout@v3 step needs this permission to fetch your source code. By restricting it to read, you prevent this job from being able to, for example, push code back to your repository, which is a great security practice
outputs block is used to pass data from one job to another job within the same workflow
pipeline where one job builds a Docker image, and a second job deploys that specific image to a server (like Amazon ECS or Kubernetes). The second job needs to know the exact tag of the image that the first job just built
the line echo "IMAGE_TAG=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT creates an output variable named IMAGE_TAG for that step
for job outputs, it’s case-insensitive, you could also do this: image_tag: ${{steps.prep.outputs.IMAGE_TAG }}
for run: steps, its case-SENSITIVE
echo "IMAGE_TAG=${GITHUB_SHA::7}" >> $GITHUB_ENV # Sets the ENV var
name: Checkout, uses: actions/checkout@v3
official action that downloads (or “checks out”) a copy of your repository’s source code onto the virtual machine (called a “runner”)
the runner = a brand new empty computer that Github spins up just for your job (no code by default), Github provides for you when your workflow starts
“Go get all the project files so the next steps can build, test, or deploy them.”
It’s almost always the first step in any workflow that needs to work with your code
run: |
The pipe | after run: is YAML syntax for a multi-line string
tells the YAML parser that the following indented lines should be treated as a single block of text, which is then executed as a shell script
echo "IMAGE_TAG=${GITHUB_SHA::7}" >> $GITHUB_ENV
GITHUB_SHA: This is a default variable provided by GitHub Actions. It contains the full 40-character commit hash that triggered the workflow
:7: This is shell syntax for creating a substring. It means “give me the first 7 characters” of the GITHUB_SHA variable
GITHUB_ENV VS GITHUB_OUTPUT
The script writes the same IMAGE_TAG information to two different special files, each with a different purpose
echo "..." >> $GITHUB_ENV
sets environment variables for subsequent steps within the same job
echo "..." >> $GITHUB_OUTPUT
sets outputs for the entire job
This is how you pass values from this job to a different job later in the workflow
Job 2
... # ---------------------------------------------------------------- # JOB 2: 새 이미지를 ECS 서비스에 배포 # ---------------------------------------------------------------- deploy-to-ecs: runs-on: ubuntu-latest needs: build-and-push steps: # AWS 자격 증명 설정 (여기서도 필요) - name: AWS CLI 설정 uses: aws-actions/configure-aws-credentials@v2 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ${{ secrets.AWS_REGION }} # 기존 ECS 태스크 정의 다운로드 - name: Download current task definition run: | aws ecs describe-task-definition --task-definition ${{ secrets.ECS_TASK_DEFINITION }} \ --query taskDefinition > task-def.json # 새 ECR 이미지로 태스크 정의 업데이트 - name: Fill in new image ID in task definition id: render-task-def uses: aws-actions/amazon-ecs-render-task-definition@v1 with: task-definition: task-def.json container-name: ${{ secrets.ECS_CONTAINER_NAME }} image: ${{ secrets.ECR_REPOSITORY_URI }}:${{ needs.build-and-push.outputs.image_tag }} # 새 태스크 정의 등록 및 ECS 서비스 업데이트 - name: Deploy Amazon ECS task definition uses: aws-actions/amazon-ecs-deploy-task-definition@v2 with: task-definition: ${{ steps.render-task-def.outputs.task-definition }} service: ${{ secrets.ECS_SERVICE }} cluster: ${{ secrets.ECS_CLUSTER }} wait-for-service-stability: false # 배포 상태 확인 - name: ECS 배포 상태 확인 run: | aws ecs describe-services \ --cluster ${{ secrets.ECS_CLUSTER }} \ --services ${{ secrets.ECS_SERVICE }} \ --query "services[0].deployments"
name: Download current task definition
Downloads your existing task definition from AWS and saves it as task-def.json
name: Fill in new image ID in task definition
Steps
Takes your existing task definition (task-def.json)
Finds the container with name ECS_CONTAINER_NAME
Updates only the image field to point to your new image (it keeps all the other settings the same coz u might want to keep them!)
Creates a new task definition file
Need to do this because task definitions are immutable in AWS
name: Deploy Amazon ECS task definition
Registers the new task definition with AWS ECS
Updates your ECS service to use this new task definition
Triggers a deployment (ECS will start new containers with the new image and stop old ones)