๊ตฌ์ถ•์„ ์œ„ํ•œ ๋””์ž์ธ ์ปจ์…‰

    / [pdf]

    / [pdf]

1. Simple Web ๋ฌด์‹ํ•˜๊ฒŒ ๋ฐฐํฌํ•˜๊ธฐ


Simple Web ์€ ์ •์  ์›น ํŽ˜์ด์ง€๋กœ ๊ตฌ์„ฑ๋œ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค. ์ด๋ฒˆ์žฅ์—์„œ๋Š” ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ํ˜„ํƒœ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ AWS ์— ๋ฐฐํฌํ•˜๋Š” ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์„ฑ์‹œ์— ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ์ˆ  ์Šคํƒ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • Terraform
  • GitHub Actions
  • AWS S3
  • AWS CodeDeploy

1. ํ”„๋กœ์ ํŠธ ํฌํฌ ํ•˜๊ธฐ

  1. GitHub ์—์„œ ํ”„๋กœ์ ํŠธ ํฌํฌ

    GitHub simple-web ์—์„œ ํ”„๋กœ์ ํŠธ ํฌํฌ โ†’ ํฌํฌ ๋ฒ„ํŠผ ํด๋ฆญ โ†’ ํฌํฌ ์ด๋ฆ„ ์ž…๋ ฅ โ†’ ํฌํฌ ์ƒ์„ฑ

  2. gh ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•œ ํฌํฌ

      gh auth status
    
    gh auth switch # ํ•„์š” ํ•˜๋‹ค๋ฉด ์ˆ˜ํ–‰ 
    
    gh repo fork https://github.com/dangtong76/simple-web.git
    
    Would you like to clone the fork? Yes # ํด๋ก ๊นŒ์ง€ ํ•œ๋ฒˆ์—
    
    # git clone  https://github.com/<your-github-id>/simple-web.git simple-web
      
  3. ์›Œํฌํ”Œ๋กœ์šฐ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ

      mkdir -p .github/workflows
    mkdir -p xinfra/aws-ec2-single
      
  4. Git ๋ธŒ๋žœ์น˜ ํ‘œ์‹œ ์„ค์ •

    vi ~/.bashrc

      # .bashrc ํŒŒ์ผ์— ์ถ”๊ฐ€
    parse_git_branch() {
      git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
    }
    
    # Git ๋ธŒ๋žœ์น˜๋ฅผ ์ปฌ๋Ÿฌ๋กœ ํ‘œ์‹œ
    export PS1="\u@\h \[\033[32m\]\w\[\033[33m\]\$(parse_git_branch)\[\033[00m\] $ "
      

    ์„ค์ • ์ ์šฉํ•˜๊ธฐ

      source ~/.bashrc
      

2. Terraform ์ฝ”๋“œ ์ƒ์„ฑ

EC2 ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
๋ณด์•ˆ ๊ทธ๋ฃน ์ถ”๊ฐ€ (์›น์„œ๋น„์Šค 80, ssh ๋ฐฐํฌ 22, ์™ธ๋ถ€์ ‘์†)
ํผ๋ธ”๋ฆญ IP ์ฃผ์†Œ ์ถ”๊ฐ€ (์„œ๋น„์Šค์œ„ํ•œ ๊ณต์ธIP)
ssh ๋ฐฐํฌ๋ฅผ ์œ„ํ•œ ํ‚ค ์ƒ์„ฑ

  1. 600_ec2.tf ์‹ ๊ทœ์ž‘์„ฑ (infra/cwave-aws-eks/600_ec2.tf)

      # TLS ํ”„๋ผ์ด๋น— ํ‚ค ์ƒ์„ฑ (๊ณต๊ฐœ ํ‚ค ํฌํ•จ)
    resource "tls_private_key" "example" {
        algorithm = "RSA"
        rsa_bits  = 2048
    }
    
    # AWS์—์„œ ํ‚ค ํŽ˜์–ด ์ƒ์„ฑ
    resource "aws_key_pair" "ec2_key" {
        key_name   = "ec2-key" # AWS์—์„œ ์‚ฌ์šฉํ•  ํ‚ค ํŽ˜์–ด ์ด๋ฆ„
        public_key = tls_private_key.example.public_key_openssh
    }
    
    # EC2 ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
    resource "aws_instance" "nginx_instance" {
        ami             = "ami-08b09b6acd8d62254" # Amazon Linux 2 AMI (๋ฆฌ์ „๋ณ„๋กœ AMI ID๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Œ)
        instance_type   = "t2.micro"
        key_name        = aws_key_pair.ec2_key.key_name # AWS์—์„œ ์ƒ์„ฑํ•œ SSH ํ‚ค ์ ์šฉ
        security_groups = [aws_security_group.nginx_sg.name]
    
        # ์ธ์Šคํ„ด์Šค๋ฅผ ๋‹ค์‹œ ๋งŒ๋“ค๋•Œ ๋น ๋ฅด๊ฒŒ ๊ต์ฒด ํ•˜๊ธฐ ์œ„ํ•œ ์˜ต์…˜
        lifecycle {
            create_before_destroy = true
        }
    
        # User ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์‹œ์— ์ธ์Šคํ„ด์Šค ์žฌ์ƒ์„ฑ ์˜ต์…˜
        user_data_replace_on_change = true
    
        # EC2 ์‹œ์ž‘ ์‹œ Nginx ์„ค์น˜ ๋ฐ ์‹คํ–‰์„ ์œ„ํ•œ User Data
        user_data = <<-EOF
                    #!/bin/bash
                    yum update -y
                    amazon-linux-extras install nginx1 -y
                    systemctl start nginx
                    systemctl enable nginx
                    EOF
        tags = {
          Name = "nginx-server"
          Environment = "Production"
        }
    }
    
    
    # ์ถœ๋ ฅ: EC2 ์ธ์Šคํ„ด์Šค์˜ ํผ๋ธ”๋ฆญ IP ์ฃผ์†Œ
    output "nginx_instance_public_ip" {
        value       = aws_instance.nginx_instance.public_ip
        description = "Public IP of the Nginx EC2 instance"
    }
    
    # ์ถœ๋ ฅ: SSH ์ ‘์†์— ์‚ฌ์šฉํ•  Private Key
    output "ssh_private_key_pem" {
        value       = tls_private_key.example.private_key_pem
        description = "Private key for SSH access"
        sensitive   = true
    }
      
  2. 200_sg.tf ์ถ”๊ฐ€์ž‘์„ฑ (infra/cwave-aws-eks/200_sg.tf)

      # ๋ณด์•ˆ ๊ทธ๋ฃน ์„ค์ •: SSH(22) ๋ฐ HTTP(80) ํŠธ๋ž˜ํ”ฝ ํ—ˆ์šฉ
    resource "aws_security_group" "nginx_sg" {
        name_prefix = "nginx-sg"
    
        ingress {
        description = "Allow SSH"
        from_port   = 22
        to_port     = 22
        protocol    = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
        }
    
        ingress {
        description = "Allow HTTP"
        from_port   = 80
        to_port     = 80
        protocol    = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
        }
    
        egress {
        from_port   = 0
        to_port     = 0
        protocol    = "-1"
        cidr_blocks = ["0.0.0.0/0"]
        }
    }
      
  3. ์‹คํ–‰

      terraform init
    terraform plan
    terraform apply
      
  4. .gitignore ํŒŒ์ผ ์ƒ์„ฑ (์ด๋ฏธ ์žˆ์œผ๋ฉด SKIP)

      .terraform
    .terraform.lock.hcl
    terraform.tfstate
    .DS_Store
    terraform.tfstate.backup
      
  5. ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋™๊ธฐํ™”

      git add .
    git commit -am "add terraform code"
    git push origin main
      

3. Github Secret ๋งŒ๋“ค๊ธฐ

  • Secret ๋ชฉ๋ก

    • IAM User Credential ์— ์„œ ์ƒ์„ฑ

      • AWS_ACCESS_KEY_ID
      • AWS_SECRET_ACCESS_KEY
    • AWS_HOST (EC2 console ์—์„œ ๋ณต์‚ฌ)

    • AWS_KEY (terraform ๋ช…๋ น์œผ๋กœ output ์ถœ๋ ฅ)

        # ์ถœ๋ ฅ๊ฒฐ๊ณผ ๋ณต์‚ฌํ•ด์„œ ์ž…๋ ฅ
      terraform output ssh_private_key_pem
        
    • AWS_USER : ec2-user (EC2 ์ธ์Šคํ„ด์Šค์˜ OS ๊ณ„์ •)

4. Github Actions ์›Œํฌํ”Œ๋กœ์šฐ ์ƒ์„ฑ

  1. ํŒŒ์ผ๋ช… : .github/workflows/simple-web-ec2-workflow.yaml ์ž‘์„ฑ

      ## .github/workflows/ec2-deploy-tough.yml
    name: AWS EC2-Deploy with Tough
    on:
      push:
        branches:
          - main
    jobs:
      deploys:
        runs-on: ubuntu-latest
        steps:
          - name: 1.์†Œ์Šค์ฝ”๋“œ ๊ฐ€์ ธ์˜ค๊ธฐ
            uses: actions/checkout@v3
          - name: 2.AWS ์ ‘์†์ •๋ณด ์„ค์ •
            uses: aws-actions/configure-aws-credentials@v3
            with:
              aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
              aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
              aws-region: ap-northeast-2
          - name: 2.SSHํ‚ค ์„ค์ •
            uses: webfactory/ssh-agent@v0.5.3
            with:
              ssh-private-key: ${{ secrets.AWS_KEY}}
          - name: 3.ํŒŒ์ผ ๋ชฉ๋ก๋ณด๊ธฐ
            run: |
              ssh -o StrictHostKeyChecking=no ${{ secrets.AWS_USER }}@${{ secrets.AWS_HOST }}  "ls -al /home/${{ secrets.AWS_USER }}"
          - name: 4.ํŒŒ์ผ ์„œ๋ฒ„๋กœ ๋ณต์‚ฌ
            run: |
              ssh -o StrictHostKeyChecking=no ${{ secrets.AWS_USER }}@${{ secrets.AWS_HOST }}  "sudo chown -R ec2-user:ec2-user /usr/share/nginx/html"
              scp -o StrictHostKeyChecking=no -r ./* ${{ secrets.AWS_USER }}@${{ secrets.AWS_HOST }}:/usr/share/nginx/html
          - name: Restart Web Server
            run: |
              ssh -o StrictHostKeyChecking=no ${{ secrets.AWS_USER }}@${{ secrets.AWS_HOST }} "sudo systemctl restart nginx || sudo systemctl restart httpd"
      
  2. ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋™๊ธฐํ™”

      git add .
    git commit -am "add github actions workflow"
    git push origin start
      
  3. ์›Œํฌํ”Œ๋กœ์šฐ ์‹คํ–‰ ๊ฒฐ๊ณผ ํ™•์ธ

    • http://<EC2 ์ธ์Šคํ„ด์Šค์˜ ํผ๋ธ”๋ฆญ IP ์ฃผ์†Œ> ์— ์ ‘์†ํ•˜์—ฌ ์›น ํŽ˜์ด์ง€ ํ™•์ธ

2. Simple Web ํ˜„๋ช…ํ•˜๊ฒŒ ๋ฐฐํฌํ•˜๊ธฐ

1. EC2์šฉ IAM ์—ญํ•  ์ƒ์„ฑํ•˜๊ธฐ

  1. EC2์šฉ IAM ์—ญํ•  ์ƒ์„ฑํ•˜๊ธฐ
    AWS ์ฝ˜์†”์—์„œ : IAM โ†’ ์—ญํ•  โ†’ ์—ญํ• ์ƒ์„ฑ

    IAM ์ด๋ฏธ์ง€

  2. ์—ญํ•  ์ƒ์„ฑ ํ™”๋ฉด์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด [ AWS ์„œ๋น„์Šค | ์„œ๋น„์Šค ๋˜๋Š” ์‚ฌ์šฉ์‚ฌ๋ก€ = EC2 | ์‚ฌ์šฉ์‚ฌ๋ก€ = EC2 ] ์„ ํƒ โ†’ ๋‹ค์Œ

    IAM ์ด๋ฏธ์ง€

  3. AWSCodeDeployFullAccess ๋ฐ AmazonS3FullAccess ์ •์ฑ… ์ถ”๊ฐ€ โ†’ ๋‹ค์Œ

    IAM ์ด๋ฏธ์ง€

  4. ์—ญํ• ์ด๋ฆ„ : simple-web-ec2-deploy-role โ†’ ๋‹ค์Œ

    IAM ์ด๋ฏธ์ง€

2. CodeDeploy์šฉ IAM ์—ญํ•  ์ƒ์„ฑ

  1. AWS ์ฝ˜์†”์—์„œ : IAM โ†’ ์—ญํ•  โ†’ ์—ญํ• ์ƒ์„ฑ
    ์—ญํ• ์ƒ์„ฑ ํ™”๋ฉด์—์„œ : [AWS ์„œ๋น„์Šค | ์„œ๋น„์Šค ๋˜๋Š” ์‚ฌ์šฉ์‚ฌ๋ก€ = CodeDeploy | ์‚ฌ์šฉ์‚ฌ๋ก€ = CodeDeploy ]

    IAM ์ด๋ฏธ์ง€

  2. ๋‚ด์šฉ ํ™•์ธํ•˜๊ณ  โ†’ ๋‹ค์Œ

    IAM ์ด๋ฏธ์ง€

  3. ์—ญํ•  ์ด๋ฆ„ : simple-web-codedeploy-role ์ž…๋ ฅ โ†’ ์—ญํ• ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ

    IAM ์ด๋ฏธ์ง€

3. Terrafrom ์ฝ”๋“œ๋กœ EC2 ์ธ์Šคํ„ด์Šค ์ˆ˜์ •

์ฝ”๋“œ ์—์ด์ „ํŠธ ์„ค์น˜๋ฅผ ์œ„ํ•œ Ruby ๋ฅผ ์„ค์น˜ ํ•ฉ๋‹ˆ๋‹ค.
Codedeploy Agent๋ฅผ ์„ค์น˜ ํ›„ ์„œ๋น„์Šค๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

  1. 600_ec2.tf ์ˆ˜์ • (infra/cwave-aws-eks/600_ec2.tf)
      resource "aws_instance" "nginx_instance" {
    subnet_id = aws_subnet.dangtong-vpc-public-subnet["a"].id
    ami             = "ami-08b09b6acd8d62254" # Amazon Linux 2 AMI (๋ฆฌ์ „๋ณ„๋กœ AMI ID๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Œ)
    instance_type   = "t2.micro"
    key_name        = aws_key_pair.ec2_key_pair.key_name # AWS์—์„œ ์ƒ์„ฑํ•œ SSH ํ‚ค ์ ์šฉ
    vpc_security_group_ids = [aws_security_group.nginx_sg.id]
    iam_instance_profile   = aws_iam_instance_profile.ec2_profile.name
    
    # ์ธ์Šคํ„ด์Šค๋ฅผ ๋‹ค์‹œ ๋งŒ๋“ค๋•Œ ๋น ๋ฅด๊ฒŒ ๊ต์ฒด ํ•˜๊ธฐ ์œ„ํ•œ ์˜ต์…˜
    lifecycle {
        create_before_destroy = true
    }
    
    # User ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์‹œ์— ์ธ์Šคํ„ด์Šค ์žฌ์ƒ์„ฑ ์˜ต์…˜
    user_data_replace_on_change = true
    
    # EC2 ์‹œ์ž‘ ์‹œ Nginx ์„ค์น˜ ๋ฐ ์‹คํ–‰์„ ์œ„ํ•œ User Data
    user_data = <<-EOF
                    #!/bin/bash
                    yum update -y
    
                    # Ruby ์„ค์น˜
                    yum install -y ruby wget
    
                    # CodeDeploy Agent ์„ค์น˜
                    cd /home/ec2-user
                    wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
                    chmod +x ./install
                    ./install auto
    
                    # CodeDeploy Agent ์„œ๋น„์Šค ์‹œ์ž‘
                    systemctl start codedeploy-agent
                    systemctl enable codedeploy-agent
    
                    # nginx ์„ค์น˜
                    amazon-linux-extras install nginx1 -y
                    systemctl start nginx
                    systemctl enable nginx
                    EOF
    tags = {
        Name        = "nginx-server"
        Environment = "Production"
    }
    }
      

4. EC2 ์ธ์Šคํ„ด์Šค์—์„œ ์—ญํ•  ์—ฐ๊ฒฐํ•˜๊ธฐ

EC2 โ†’ ์ธ์Šคํ„ด์Šค โ†’ ์ธ์Šคํ„ด์Šค ID โ†’ ์ž‘์—… โ†’ ๋ณด์•ˆ โ†’ IAM ์—ญํ• ์ˆ˜์ • โ†’ IAM ์—ญํ•  ์„ ํƒ โ†’ simple-web-ec2-deploy-role ์„ ํƒ โ†’ IAM ์—ญํ•  ์—…๋ฐ์ดํŠธ

IAM ์ด๋ฏธ์ง€

5. S3 ๋ฒ„ํ‚ท ๋งŒ๋“ค๊ธฐ

S3 ํ™”๋ฉด์—์„œ โ†’ ๋ฒ„ํ‚ท ๋งŒ๋“ค๊ธฐ ํด๋ฆญ
๋ฒ„ํ‚ท์ด๋ฆ„ : simple-web-content
๋‚˜๋จธ์ง€๋Š” ๋ชจ๋‘ Default ๋กœ ์ƒ์„ฑ

S3 ์ด๋ฏธ์ง€

6. CodeDeploy ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋งŒ๋“ค๊ธฐ

codedeploy โ†’ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ โ†’ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ
์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ด๋ฆ„ : simple-web-content

CodeDeploy ์ด๋ฏธ์ง€

7. CodeDeploy ๋ฐฐํฌ ๊ทธ๋ฃน ๋งŒ๋“ค๊ธฐ

  • ๋ฐฐํฌ ๊ทธ๋ฃน ์ƒ์„ฑ

    codedeploy โ†’ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ โ†’ ๋ฐฐํฌ ๊ทธ๋ฃน ์ƒ์„ฑ

    ๋ฐฐํฌ๊ทธ๋ฃน์ด๋ฆ„์ž…๋ ฅ : simple-web-deploy-group

    ์„œ๋น„์Šค์—ญํ•  : simple-web-codedeploy-role

    CodeDeploy ์ด๋ฏธ์ง€
  • ๊ณ„์†

    ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐฐํฌ ๋ฐฉ๋ฒ• : ํ˜„์žฌ ์œ„์น˜

    ํ™˜๊ฒฝ๊ตฌ์„ฑ : Amazon EC2 ์ธ์Šคํ„ด์Šค

    ํƒœ๊ทธ ๊ทธ๋ฃน : ํ‚ค = Environment | ๊ฐ’ = Production

    ๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ ์ฒดํฌ ๋ฐ•์Šค ๋น„ํ™œ์„ฑํ™”

    CodeDeploy ์ด๋ฏธ์ง€

8. Github Action Secret ์—…๋ฐ์ดํŠธ

์•„๋ž˜ SECRET ์—…๋ฐ์ดํŠธ ํ•ด์ฃผ๊ธฐ

AWS_HOST

AWS_BUCKET

9. Github Action Workflow ์ž‘์„ฑํ•˜๊ธฐ

AWS CodeDploy๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด appspec.yml ๋ฐ˜๋“œ์‹œ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์„œ๋น„์Šค๋ฅผ ์ค‘์ง€,์‹œ์ž‘ ํ•˜๊ธฐ ์œ„ํ•œ ์Šคํฌ๋ฆฝํŠธ๋Š” ํ•„์š”ํ•˜๋ฉด ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

  1. ๊ธฐ์กด ์›Œํฌ ํ”Œ๋กœ์šฐ ๋น„ํ™œ์„ฑํ™”
  gh workflow list
  
  gh workflow disable
  
  1. ์ƒˆ๋กœ์šด workflow ํŒŒ์ผ ์ž‘์„ฑ

      ## .github/workflows/ec2-deploy-smart.yml
    name: AWS EC2-Deploy with Smart
    on:
      push:
        branches: [main]
    
    jobs:
      deploy:
        runs-on: ubuntu-latest
        steps:
          - name: 1.์†Œ์Šค์ฝ”๋“œ ๋‹ค์šด๋กœ๋“œ (simple-web)
            uses: actions/checkout@v2
    
          - name: 2.AWS CLI ์ ‘์†์ •๋ณด ์„ค์ •
            uses: aws-actions/configure-aws-credentials@v4
            with:
              aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
              aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
              aws-region: ap-northeast-2
    
          - name: 3.์•„ํ‹ฐํŒฉํŠธ ๋งŒ๋“ค๊ธฐ
            run: |
              pwd
              zip -r deploy.zip ./*
    
          - name: 4.S3 ์•„ํ‹ฐํŒฉํŠธ ์—…๋กœ๋“œ
            run: |
              aws s3 cp deploy.zip s3://${{ secrets.AWS_BUCKET }}/deploy.zip
    
          - name: 5.ํ˜„์žฌ ์ง„ํ–‰์ค‘์ธ AWS Deploy ID ๊ฐ€์ ธ์˜ค๊ณ  ์ค‘๋‹จ ์‹œํ‚จ๋‹ค. 
            run: |
              DEPLOYMENTS=$(aws deploy list-deployments \
                --application-name simple-web-content \
                --deployment-group-name simple-web-deploy-group \
                --include-only-statuses "InProgress" \
                --query 'deployments[]' \
                --output text)
    
              if [ ! -z "$DEPLOYMENTS" ]; then
                for deployment in $DEPLOYMENTS; do
                  echo "Stopping deployment $deployment"
                  aws deploy stop-deployment --deployment-id $deployment
                done
                # ์ž ์‹œ ๋Œ€๊ธฐํ•˜์—ฌ ์ทจ์†Œ๊ฐ€ ์™„๋ฃŒ๋˜๋„๋ก ํ•จ
                sleep 10
              fi
    
          - name: 6. AWS Deploy๋ฅผ ํ†ตํ•ด ๋ฐฐํฌํ•œ๋‹ค
            id: deploy
            run: |
              DEPLOYMENT_ID=$(aws deploy create-deployment \
                --application-name simple-web-content \
                --deployment-group-name simple-web-deploy-group \
                --s3-location bucket=${{ secrets.AWS_BUCKET }},key=deploy.zip,bundleType=zip \
                --output text \
                --query 'deploymentId')
              #echo "::set-output name=deployment_id::$DEPLOYMENT_ID"
              #echo "{name}=deployment_id" >> $GITHUB_OUTPUT
              echo "deployment_id=${DEPLOYMENT_ID}" >> $GITHUB_OUTPUT
    
          - name: Wait for deployment to complete
            run: |
              aws deploy wait deployment-successful --deployment-id ${{ steps.deploy.outputs.deployment_id }}
      
  2. ์Šคํฌ๋ฆฝํŠธ ๋“ฑ๋ก

    scripts/before_install.sh

      #!/bin/bash
    # ๊ธฐ์กด ํŒŒ์ผ ์‚ญ์ œ
    if [ -d /usr/share/nginx/html ]; then
        rm -rf /usr/share/nginx/html/*
    fi
      

    scripts/after_install.sh

      #!/bin/bash
    # ํŒŒ์ผ ๊ถŒํ•œ ๋ณ€๊ฒฝ
    chmod -R 755 /usr/share/nginx/html
    chown -R nginx:nginx /usr/share/nginx/html
    # ์›น์„œ๋ฒ„ ์žฌ์‹œ์ž‘
    systemctl restart nginx
      
  3. appspec.yml ๋“ฑ๋กํ•˜๊ธฐ

      version: 0.0                # AppSpec ํŒŒ์ผ ๋ฒ„์ „
    os: linux                   # ๋ฐฐํฌ ๋Œ€์ƒ ์šด์˜์ฒด์ œ
    
    files:                      # ๋ณต์‚ฌํ•  ํŒŒ์ผ ๋ฐ ๋””๋ ‰ํ„ฐ๋ฆฌ ๋ชฉ๋ก
      - source: /               # ์†Œ์Šค ๋””๋ ‰ํ„ฐ๋ฆฌ(์ „์ฒด)
        destination: /usr/share/nginx/html/   # ๋ณต์‚ฌ ๋Œ€์ƒ ๊ฒฝ๋กœ
        overwrite: true         # ๊ธฐ์กด ํŒŒ์ผ ๋ฎ์–ด์“ฐ๊ธฐ ํ—ˆ์šฉ
    
    permissions:                # ํŒŒ์ผ ๋ฐ ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ถŒํ•œ ์„ค์ •
      - object: /usr/share/nginx/html         # ๊ถŒํ•œ์„ ์ ์šฉํ•  ๋””๋ ‰ํ„ฐ๋ฆฌ
        pattern: "**"                         # ๋ชจ๋“  ํ•˜์œ„ ๋””๋ ‰ํ„ฐ๋ฆฌ ํฌํ•จ
        owner: nginx                          # ์†Œ์œ ์ž
        group: nginx                          # ๊ทธ๋ฃน
        mode: 755                             # ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ถŒํ•œ
        type:
          - directory                         # ๋””๋ ‰ํ„ฐ๋ฆฌ์—๋งŒ ์ ์šฉ
      - object: /usr/share/nginx/html         # ๊ถŒํ•œ์„ ์ ์šฉํ•  ๋””๋ ‰ํ„ฐ๋ฆฌ
        pattern: "**/*"                       # ๋ชจ๋“  ํŒŒ์ผ ํฌํ•จ
        owner: nginx                          # ์†Œ์œ ์ž
        group: nginx                          # ๊ทธ๋ฃน
        mode: 644                             # ํŒŒ์ผ ๊ถŒํ•œ
        type:
          - file                              # ํŒŒ์ผ์—๋งŒ ์ ์šฉ
    
    hooks:                                    # ๋ฐฐํฌ ๋ผ์ดํ”„์‚ฌ์ดํด ํ›…
      BeforeInstall:                          # ์„ค์น˜ ์ „ ์‹คํ–‰ํ•  ์Šคํฌ๋ฆฝํŠธ
        - location: scripts/before_install.sh # ์Šคํฌ๋ฆฝํŠธ ๊ฒฝ๋กœ
          timeout: 300                        # ํƒ€์ž„์•„์›ƒ(์ดˆ)
          runas: root                         # ์‹คํ–‰ ์‚ฌ์šฉ์ž
      AfterInstall:                           # ์„ค์น˜ ํ›„ ์‹คํ–‰ํ•  ์Šคํฌ๋ฆฝํŠธ
        - location: scripts/after_install.sh  # ์Šคํฌ๋ฆฝํŠธ ๊ฒฝ๋กœ
          timeout: 300                        # ํƒ€์ž„์•„์›ƒ(์ดˆ)
          runas: root                         # ์‹คํ–‰ ์‚ฌ์šฉ์ž
      
  4. ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋™๊ธฐํ™” ํ•˜๊ธฐ

      git add .
    git commit -am "add github actions workflow"
    git push origin start
      
  5. AWS EC2 ์ธ์Šคํ„ด์Šค์—์„œ Agent ๋ฐฐํฌ ๋กœ๊ทธ ํ™•์ธํ•˜๊ธฐ

      sudo tail -f /var/log/aws/codedeploy-agent/codedeploy-agent.log
      

3. Simple Web ์™„๋ฒฝํ•˜๊ฒŒ ๋ฐฐํฌ ํ•˜๊ธฐ

1. EC2 ์ˆ˜์ •

  # EC2 ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
resource "aws_instance" "nginx_instance" {
    ami             = "ami-08b09b6acd8d62254" # Amazon Linux 2 AMI (๋ฆฌ์ „๋ณ„๋กœ AMI ID๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Œ)
    instance_type   = "t2.micro"
    key_name        = aws_key_pair.ec2_key.key_name # AWS์—์„œ ์ƒ์„ฑํ•œ SSH ํ‚ค ์ ์šฉ
    security_groups = [aws_security_group.nginx_sg.name]

    # ์ž‘์—… -> ๋ณด์•ˆ -> IAM ์—ญํ•  ์ˆ˜์ • 
    iam_instance_profile = aws_iam_instance_profile.ec2_profile.name

    # ์ธ์Šคํ„ด์Šค๋ฅผ ๋‹ค์‹œ ๋งŒ๋“ค๋•Œ ๋น ๋ฅด๊ฒŒ ๊ต์ฒด ํ•˜๊ธฐ ์œ„ํ•œ ์˜ต์…˜
    lifecycle {
        create_before_destroy = true
    }
    # User ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์‹œ์— ์ธ์Šคํ„ด์Šค ์žฌ์ƒ์„ฑ ์˜ต์…˜
    user_data_replace_on_change = true
    # EC2 ์‹œ์ž‘ ์‹œ Nginx ์„ค์น˜ ๋ฐ ์‹คํ–‰์„ ์œ„ํ•œ User Data
    user_data = <<-EOF
                #!/bin/bash
                yum update -y

                # Ruby ์„ค์น˜
                yum install -y ruby wget

                # CodeDeploy Agent ์„ค์น˜
                cd /home/ec2-user
                wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
                chmod +x ./install
                ./install auto

                # CodeDeploy Agent ์„œ๋น„์Šค ์‹œ์ž‘
                systemctl start codedeploy-agent
                systemctl enable codedeploy-agent

                # nginx ์„ค์น˜
                amazon-linux-extras install nginx1 -y
                systemctl start nginx
                systemctl enable nginx

                # ์žฌ์ƒ์„ฑ์„ ์œ„ํ•œ ์—์ฝ”
                echo "1"
                EOF
    tags = {
      Name = "nginx-server"
      Environment = "Production"
    }
}
  

2. IAM ์ƒ์„ฑ

ํŒŒ์ผ๋ช… : 400_iam.tf ์ž‘์„ฑ [์ถ”๊ฐ€]

  # GitHub Actions์šฉ IAM ์—ญํ•  ์ƒ์„ฑ
resource "aws_iam_role" "github_actions_role" {
  name = "GithubActionsRole"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
        }
      }
    ]
  })

  tags = {
    Name = "github-actions-role"
  }
}

# CodeDeploy๋ฅผ ์œ„ํ•œ EC2 IAM ์—ญํ• 
resource "aws_iam_role" "ec2_codedeploy_role" {
  name = "EC2CodeDeployRole"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      }
    ]
  })

  tags = {
    Name = "ec2-codedeploy-role"
  }
}

# CodeDeploy ์„œ๋น„์Šค ์—ญํ• 
resource "aws_iam_role" "codedeploy_service_role" {
  name = "CodeDeployServiceRole"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "codedeploy.amazonaws.com"
        }
      }
    ]
  })

  tags = {
    Name = "codedeploy-service-role"
  }
}

# GitHub Actions ์—ญํ• ์— ์ •์ฑ… ์—ฐ๊ฒฐ
resource "aws_iam_role_policy_attachment" "github_actions_s3" {
  role       = aws_iam_role.github_actions_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
}

resource "aws_iam_role_policy_attachment" "github_actions_codedeploy" {
  role       = aws_iam_role.github_actions_role.name
  policy_arn = "arn:aws:iam::aws:policy/AWSCodeDeployFullAccess"
}

# EC2 ์ธ์Šคํ„ด์Šค ์—ญํ• ์— ์ •์ฑ… ์—ฐ๊ฒฐ
resource "aws_iam_role_policy_attachment" "ec2_codedeploy_s3" {
  role       = aws_iam_role.ec2_codedeploy_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
}

resource "aws_iam_role_policy_attachment" "ec2_codedeploy" {
  role       = aws_iam_role.ec2_codedeploy_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole"
}

# CodeDeploy ์„œ๋น„์Šค ์—ญํ• ์— ์ •์ฑ… ์—ฐ๊ฒฐ
resource "aws_iam_role_policy_attachment" "codedeploy_service" {
  role       = aws_iam_role.codedeploy_service_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole"
}

# EC2 ์ธ์Šคํ„ด์Šค ํ”„๋กœํŒŒ์ผ ์ƒ์„ฑ
resource "aws_iam_instance_profile" "ec2_profile" {
  name = "EC2CodeDeployProfile"
  role = aws_iam_role.ec2_codedeploy_role.name
}

# ์ถœ๋ ฅ: GitHub Actions ์—ญํ•  ARN
output "github_actions_role_arn" {
  value       = aws_iam_role.github_actions_role.arn
  description = "ARN of the GitHub Actions IAM Role"
}
  

3. S3 ์‹ ๊ทœ ์ƒ์„ฑ

ํŒŒ์ผ๋ช… : 700_s3.tf [์‹ ๊ทœ]

  # S3 ๋ฒ„ํ‚ท ์ƒ์„ฑ
resource "aws_s3_bucket" "deploy_bucket" {
  bucket = "simple-web-deploy-bucket-${data.aws_caller_identity.current.account_id}"  # ๊ณ ์œ ํ•œ ๋ฒ„ํ‚ท ์ด๋ฆ„ ํ•„์š”
}

# S3 ๋ฒ„ํ‚ท ๋ฒ„์ „ ๊ด€๋ฆฌ ์„ค์ •
resource "aws_s3_bucket_versioning" "deploy_bucket_versioning" {
  bucket = aws_s3_bucket.deploy_bucket.id
  versioning_configuration {
    status = "Enabled"
  }
}

# S3 ๋ฒ„ํ‚ท ์ด๋ฆ„ ์ถœ๋ ฅ
output "deploy_bucket_name" {
  value       = aws_s3_bucket.deploy_bucket.id
  description = "Name of the S3 bucket for deployments"
}
  

4. codedeploy ์ƒ์„ฑ

ํŒŒ์ผ๋ช… : 800_codedeploy.tf [์‹ ๊ทœ]

  # CodeDeploy ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ
resource "aws_codedeploy_app" "web_app" {
  name = "simple-web-content2"
}

# CodeDeploy ๋ฐฐํฌ ๊ทธ๋ฃน ์ƒ์„ฑ
resource "aws_codedeploy_deployment_group" "web_deploy_group" {
  app_name               = aws_codedeploy_app.web_app.name
  deployment_group_name  = "simple-web-deploy-group"
  service_role_arn      = aws_iam_role.codedeploy_service_role.arn

  deployment_style {
    deployment_option = "WITHOUT_TRAFFIC_CONTROL"
    deployment_type   = "IN_PLACE"
  }

  ec2_tag_set {
    ec2_tag_filter {
      key   = "Environment"
      type  = "KEY_AND_VALUE"
      value = "Production"
    }
  }

  auto_rollback_configuration {
    enabled = true
    events  = ["DEPLOYMENT_FAILURE"]
  }

  alarm_configuration {
    enabled = false
  }
}

# CodeDeploy ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ด๋ฆ„ ์ถœ๋ ฅ
output "codedeploy_app_name" {
  value       = aws_codedeploy_app.web_app.name
  description = "Name of the CodeDeploy application"
}

# CodeDeploy ๋ฐฐํฌ ๊ทธ๋ฃน ์ด๋ฆ„ ์ถœ๋ ฅ
output "codedeploy_deployment_group_name" {
  value       = aws_codedeploy_deployment_group.web_deploy_group.deployment_group_name
  description = "Name of the CodeDeploy deployment group"
} 
  

5. ์›Œํฌํ”Œ๋กœ์šฐ Disable ๋ฐ Github ์…‹ํŒ…

  • ์›Œํฌํ”Œ๋กœ์šฐ Disable
  gh workflow disable
  
  • Github Secret AWS_BUCKET ๋ณ€๊ฒฝ

6. ์‹ ๊ทœ ํŒŒ์ดํ”„๋ผ์ธ ์ถ”๊ฐ€

  ## .github/workflows/ec2-deploy-smart.yml
name: AWS EC2-Deploy with Perfect
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: 1.์†Œ์Šค์ฝ”๋“œ ๋‹ค์šด๋กœ๋“œ (simple-web)
        uses: actions/checkout@v2

      - name: 2.AWS CLI ์ ‘์†์ •๋ณด ์„ค์ •
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-2

      - name: 3.์•„ํ‹ฐํŒฉํŠธ ๋งŒ๋“ค๊ธฐ
        run: |
          pwd
          zip -r deploy.zip ./*

      - name: 4.S3 ์•„ํ‹ฐํŒฉํŠธ ์—…๋กœ๋“œ
        run: |
          aws s3 cp deploy.zip s3://${{ secrets.AWS_BUCKET }}/deploy.zip

      - name: 5.ํ˜„์žฌ ์ง„ํ–‰์ค‘์ธ AWS Deploy ID ๊ฐ€์ ธ์˜ค๊ณ  ์ค‘๋‹จ ์‹œํ‚จ๋‹ค.
        run: |
          DEPLOYMENTS=$(aws deploy list-deployments \
            --application-name simple-web-content2 \
            --deployment-group-name simple-web-deploy-group \
            --include-only-statuses "InProgress" \
            --query 'deployments[]' \
            --output text)

          if [ ! -z "$DEPLOYMENTS" ]; then
            for deployment in $DEPLOYMENTS; do
              echo "Stopping deployment $deployment"
              aws deploy stop-deployment --deployment-id $deployment
            done
            # ์ž ์‹œ ๋Œ€๊ธฐํ•˜์—ฌ ์ทจ์†Œ๊ฐ€ ์™„๋ฃŒ๋˜๋„๋ก ํ•จ
            sleep 10
          fi

      - name: 6. AWS Deploy๋ฅผ ํ†ตํ•ด ๋ฐฐํฌํ•œ๋‹ค
        id: deploy
        run: |
          DEPLOYMENT_ID=$(aws deploy create-deployment \
            --application-name simple-web-content2 \
            --deployment-group-name simple-web-deploy-group \
            --s3-location bucket=${{ secrets.AWS_BUCKET }},key=deploy.zip,bundleType=zip \
            --output text \
            --query 'deploymentId')
          #echo "::set-output name=deployment_id::$DEPLOYMENT_ID"
          #echo "{name}=deployment_id" >> $GITHUB_OUTPUT
          echo "deployment_id=${DEPLOYMENT_ID}" >> $GITHUB_OUTPUT

      - name: Wait for deployment to complete
        run: |
          aws deploy wait deployment-successful --deployment-id ${{ steps.deploy.outputs.deployment_id }}
  

7. ์†Œ์Šค ์ˆ˜์ • ๋ฐ ๋ฐฐํฌ

simple-web/index.html

  <!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Last</title>
    <link rel="stylesheet" href="style.css" />
    <link
  
  • ์ปค๋ฐ‹ ๋ฐ Push
  git commit -am "deploy perfect"
git push origin main
  

4. Simple WEB ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์— ๋ฉ”๋‰ด์–ผ ๋ฐฐํฌํ•˜๊ธฐ

1. Docker ํŒŒ์ผ ์ž‘์„ฑ

  FROM nginx:alpine

# ๊ธฐ์กด nginx ๊ธฐ๋ณธ ํŽ˜์ด์ง€ ์ œ๊ฑฐ
RUN rm -rf /usr/share/nginx/html/*

# ์›น ํŒŒ์ผ๋“ค์„ ์ปจํ…Œ์ด๋„ˆ๋กœ ๋ณต์‚ฌ
COPY index.html /usr/share/nginx/html/
COPY style.css /usr/share/nginx/html/
COPY assets/ /usr/share/nginx/html/assets/
COPY scripts/ /usr/share/nginx/html/scripts/

# nginx ํฌํŠธ ๋…ธ์ถœ
EXPOSE 80

# nginx ์‹คํ–‰
CMD ["nginx", "-g", "daemon off;"]
  

2. ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ๋นŒ๋“œ

  docker build -t <your-dockerhub-id>/simple-web .
  

3. ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ํ‘ธ์‹œ

  docker login --username <your-dockerhub-id>
docker push <your-dockerhub-id>/simple-web
  

4. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋ฐฐํฌ

  1. simple-web-deploy.yaml ํŒŒ์ผ ์ƒ์„ฑ
  apiVersion: apps/v1
kind: Deployment
metadata:
  name: simple-web
  labels:
    app: simple-web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: simple-web
  template:
    metadata:
      labels:
        app: simple-web
    spec:
      containers:
        - name: simple-web
          image: <your-dockerhub-id>/simple-web
          ports:
            - containerPort: 80 
  
  1. simple-web-ingress.yaml ํŒŒ์ผ ์ƒ์„ฑ
  apiVersion: v1
kind: Service
metadata:
  name: simple-web-lb
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: external
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
    service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
spec:
  type: LoadBalancer
  selector:
    app: simple-web
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 800
  ports:
    - name: simple-web
      protocol: TCP
      port: 80
      targetPort: 80
  

5. Github workflow ์ž‘์„ฑ

  • Github Action Secret ์ž‘์„ฑ
    DOCKER_USERNAME
    DOCKER_TOKEN # Docker hub Token
    PAT # Github token
  • yml ํŒŒ์ผ ์ž‘์„ฑ
  name: simple-web-eks-ci

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

permissions:
  contents: read
  actions: read

jobs:
  build:

    runs-on: ubuntu-latest
    env:
      DOCKER_IMAGE: ${{ secrets.DOCKER_USERNAME }}/simple-web
      DOCKER_TAG: ${{ github.run_number }}

    steps:
      - name: 1.์†Œ์Šค์ฝ”๋“œ ๋‹ค์šด๋กœ๋“œ
        uses: actions/checkout@v4 

      - name: 7.Docker Image Build
        run: docker build  -t ${{ secrets.DOCKER_USERNAME }}/simple-web:${{ env.DOCKER_TAG }} .

      - name: 8.Docker Login
        uses: docker/login-action@v3.0.0
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}
          logout: true

      - name: 9.Docker Push
        run: |
          docker push ${{ secrets.DOCKER_USERNAME }}/simple-web:${{ env.DOCKER_TAG }}

      # ์„œ๋น„์Šค ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ฒดํฌ์•„์›ƒ
      - name: 10.์„œ๋น„์Šค ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ฒดํฌ์•„์›ƒ
        uses: actions/checkout@v4
        with:
          repository: dangtong-s-inc/simple-service  
          ref: main
          path: .
          token: ${{ secrets.PAT }} 
      
      # ์ด๋ฏธ์ง€ ํƒœ๊ทธ ์—…๋ฐ์ดํŠธ
      - name: 11.์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋งค๋‹ˆํŽ˜์ŠคํŠธ ํŒŒ์ผ ์ด๋ฏธ์ง€ ํƒœ๊ทธ ์—…๋ฐ์ดํŠธ
        run: |
          # ํŒŒ์ผ์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
          ls -la
          # ํ˜„์žฌ ํŒŒ์ผ ๋‚ด์šฉ ํ™•์ธ
          cat simple-deploy.yaml
          sed -i "s|image: ${{ secrets.DOCKER_USERNAME }}\/simple-web.*|image: ${{ secrets.DOCKER_USERNAME }}\/simple-web:${{ env.DOCKER_TAG }}|g" simple-deploy.yaml
          # ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ ํ™•์ธ
          cat simple-deploy.yaml
      
      # ๋ณ€๊ฒฝ์‚ฌํ•ญ ์ปค๋ฐ‹ ๋ฐ ํ‘ธ์‹œ
      - name: 12.์„œ๋น„์Šค ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋ณ€๊ฒฝ์‚ฌํ•ญ ์ปค๋ฐ‹ ๋ฐ ํ‘ธ์‹œ
        run: |
          git config --global user.name 'github-actions[bot]'
          git config --global user.email 'github-actions[bot]@users.noreply.github.com'
          git commit -am "Update image tag to ${{ env.DOCKER_TAG }}"
          git remote set-url origin https://${{ secrets.PAT }}@github.com/${{ secrets.DOCKER_USERNAME }}/simple-service.git
          
          git push origin main