(1) 프로젝트 개요
(1) Deployment
(2) Iac (Infrastructure as Code)
(3) CI/CD (Continuous Integration/Continuous Delivery)
(1) 프로젝트 진행 과정
(1) 인프라 구조
(1) Frontend GitHub Repository
(2) Backend GitHub Repository
(3) 앱 디렉터리 구조
(4) Terraform GitHub Repository
(5) Terraform 디렉터리 구조
(1) 계정 권한
(2) 키
(3) 그룹 당 규칙
(4) 역할
(1) 초기 설정
(2) Amazon S3 설정
(3) Amazon S3에 배포
(4) 서비스 정상 작동 확인
(1) Amazon S3만으로 정적 웹 호스팅을 서비스할 때 문제점
(2) 초기 설정
(3) AWS CloudFront 설정
(4) 서비스 정상 작동 확인
(1) 초기 설정
(2) Amazon EC2 설정
(1) 초기 설정
(2) Amazon RDS 설정
(3) Database 설정
(1) 초기 설정-1
(2) 초기 설정-2
(1) terraform apply
(1) VPC 구성 확인
(2) Amazon EC2 확인
(3) Amazon S3 확인
(4) Amazon RDS 확인
(1) GitHub Actions
(2) React test 코드를 삽입 후 GitHub에 commit 시 자동으로 배포
(1) AWS CodeDeploy
(2) GitHub Actions
(3) Flask test 코드를 삽입 후 GitHub에 commit 시 자동으로 배포
(1) autoprefixer
(2) eslint: img alt
(3) eslint: eqeqeq
(1) 배포했으나 연결할 수 없음
(2) 해결 방법
(3) 정상 작동 확인
(1) Backend와 Database 연동이 안 됨
(2) 해결 방법
(3) 재 배포 시 정상으로 작동하는 것을 확인
(1) Frotnend와 Backend 연동이 안 됨
(2) 해결 방법
(3) 재 배포 시 정상으로 작동하는 것을 확인
(4) SSL 인증-1
(5) SSL 인증-2
(1) 이미지 업로드가 안 됨
(2) 직접 EC2 내부로 들어가서 작업
(3) 백그라운드로 실행시키고 있는 Flask를 종료 후 포그라운드로 실행한 다음 요청 및 응답을 확인
(4) 디렉터리가 존재하지 않는 이유
(5) AWS CodeDeploy를 잘못 이해하고 있었음
(6) 해결 방법
(7) 재 배포 시 정상적으로 작동하는 것을 확인
(1) Crontab 작동이 안함
(2) 해결 방법
(3) 재 배포 시 정상적으로 작동하는 것을 확인
(1) deploy.yml 템플릿 수정
(2) 캐시 설정 전
(3) 캐시 설정 후
- 프로젝트 이름: SSGBay-v4
- 프로젝트 목적:
- 기존의 SSGBay 애플리케이션을 AWS에 배포
- Terraform을 이용해 인프라를 코드로 자동 구성
- GitHub Actions와 AWS CodeDeploy를 이용해 CI/CD 파이프라인 구축
- 해당 서비스 앱의 main branch에서 커밋하면 자동으로 배포
- 프로젝트 기간: 2023.11.22 ~ 2023.11.28
- Amazon Web Service (EC2, S3, CloudFront, RDS)
- Terraform
- GitHub Actions & AWS CodeDeploy
일별 | 내용 |
---|---|
1일차 (11.22) | AWS를 이용한 기본 배포 |
2일차 (11.23) | Terraform을 이용한 인프라 자동화 |
3일차 (11.24) | GitHub Actions와 AWS CodeDeploy를 이용한 CI/CD 파이프라인 구성 |
4~7일차 (11.25 ~ 11.28) | Trouble Shooting |
📁 client
├──── 📁 .github
│ └──── 📁 workflows
│ └──── 📄 deploy.yml
│ └──── 📄 deploy.yml
...
...
📁 server
├──── 📁 .github
│ └──── 📁 workflows
│ └──── 📄 deploy.yml
├──── 📁 scripts
│ ├──── 📄 afterInstall.sh
│ ├──── 📄 beforeInstall.sh
│ └──── 📄 runServer.sh
├─────────── 📄 appspec.yml
...
...
-
workflows/deploy.yml
- Github Actions를 이용해 자동화한 작업 과정
- 폴더 아래에 위치한 YAML 파일로 작업 과정을 설정
- 하나의 코드 저장소(GitHub Repository)에 여러 개의 워크플로우 설정이 가능
- 해당 워크플로우는
on
속성을 이용해 언제 실행되는지와job
속성을 이용해 구체적으로 어떤 일을 하는지 명시
-
appspec.yml
- AWS CodeDeploy를 이용해 자동화한 작업 과정
- React 앱은 Amazon EC2가 아닌 Amazon S3에 정적 상태로 저장하기 때문에 사용하지 않음
-
scripts
- appspec.yml에 사용할 shell script들이 있는 폴더
📁 terraform
├──── 📁 .terraform
├──── 📁 permission
│ ├──── 📄 iamPolicyFlask.tf
│ ├──── 📄 iamPolicyMySQL.tf
│ ├──── 📄 iamPolicyReact.tf
│ └──── 📄 rlatkdCodeDeployEC2Policy.tf
├──── 📁 module
│ ├──── 📄 ec2.tf
│ ├──── 📄 ec2RdsSg.tf
│ ├──── 📄 ec2Sg.tf
│ ├──── 📄 iam.tf
│ ├──── 📄 rds.tf
│ ├──── 📄 rdsEc2Sg.tf
│ ├──── 📄 role.tf
│ ├──── 📄 s3React.tf
│ └──── 📄 vpc.tf
├─────────── 📄 .terraform.lock.hcl
├─────────── 📄 main.tf
├─────────── 📄 terraform.tfstate
└─────────── 📄 terraform.tfstate.backup
-
.terraform
terraform init
명령어를 실행하면 프로바이더를 참조하여 해당 환경을 설정해주는 파일을 모아둔 폴더
-
permission
- 각 사용자 및 Amazon EC2에 쓰일 정책 모음 폴더
-
module
- 서비스 별로 나누어 권한, 정책, 생성 등을 명시한 폴더
-
.terraform.lock.hcl
-
파일 위치를 잠금으로서 두 작업이 비동기적으로 처리되게 설정하는 파일
-
terraform init
명령어를 실행할 때 마다 자동으로 생성하거나 업데이트
-
-
main.tf
terraform apply
명령어를 실행하면 각 resource 들에 명시된대로 인프라 구성 및 설정
-
.terraform.tfstate
- JSON 형태로 되어있으며, terraform으로 구성된 인프라의 현재 상태를 보여줌
-
.terraform.tfstate.backup
- JSON 형태로 되어있으며, terraform으로 구성된 인프라를 백업하여 나중에 복구할 수 있도록 해줌
User | permission |
---|---|
rlatkdReact | AmazonS3FullAccess |
rlatkdFlask | AmazonEC2FullAccess, AmazonS3FullAccess, AWSCodeDeployFullAccess |
rlatkdMySQL | AmazonEC2FullAccess, AmazonRDSFullAccess |
rlatkdTerraform | AdministratorAccess |
Service | KeyPair |
---|---|
Amazon EC2 | rlatkdKeyPair |
Service | AccessKey |
---|---|
Terraform | rlatkdTerraform |
GitHubActions - React | rlatkdReact |
GitHubActions - Flask | rlatkdFlask |
InBound Rule | Security Group: rlatkdFlaskWebServserSg |
---|---|
Protocol | TCP |
Port | 5000 |
Source | 0.0.0.0/0 |
OutBound Rule | Security Group: rlatkd-ec2-rds-Sg |
---|---|
Type | MySQL/Aurora |
Protocol | TCP |
Port | 3306 |
Target | rlatkd-rds-ec2-Sg |
InBound Rule | Security Group: rlatkd-rds-ec2-Sg |
---|---|
Type | MySQL/Aurora |
Protocol | TCP |
Port | 3306 |
Source | rlatkd-ec2-rds-Sg |
Service | Role |
---|---|
Amazon EC2 | rlatkdEC2AccessS3Role (rlatkdCodeDeployEC2Policy) |
AWS CodeDeploy Group | rlatkdCodeDeployRole |
GitHubActions - Flask | AccessKey: rlatkdFlask AK |
.\client>npm install
.\client>npm run build
.\CLIENT\BUILD
│ asset-manifest.json
│ favicon.ico
│ index.html
│ logo192.png
│ logo512.png
│ manifest.json
│ robots.txt
│
└───static
├───css
│ main.3b876a84.css
│ main.3b876a84.css.map
│
└───js
787.cda612ba.chunk.js
787.cda612ba.chunk.js.map
main.37105d08.js
main.37105d08.js.LICENSE.txt
main.37105d08.js.map
https
가 아닌http
통신을 해야 한다는 점- Amazon S3이 퍼블릭 공개라는 점
- Amazon S3의 엔드포인트 주소를 그대로 사용해야 한다는 점
- 해결하기 위해선 AWS CloudFront를 이용
- AWS Global Edge Server를 통해 CDN(Content Delivery Network) 역할을 해주는 AWS 서비스
- OAI를 설정하면 Amazon S3에 퍼블릭으로 공개하지 않고도 AWS CloudFront를 통해서 Amazon S3에 퍼블릭으로 접근할 수 있음
- 동시에 AWS CloudFront를 우회하여 Amazon S3에 직접 액세스할 수 없음
- AWS CloudFront에서 캐싱 계층을 하나 더 추가하여 사용자(클라이언트)와 엣지 서버간의 거리를 줄이는 기능
- 캐시 적중률을 높이고 오리진 서버의 부하를 줄여주어 로드 속도를 향상시키는 효과가 있음
- Origin Shield를 활성화하면 요청이 Origin Shield를 경유할 때마다 비용이 추가로 발생
- 자동으로 객체 압축을 Yes로 설정 -> 요청할 리소스의 파일 크기를 비약적으로 줄여줄 수 있음
- 뷰어 프로토콜 정책는 Redirect HTTP to HTTPS로 설정 -> HTTP 프로토콜로 접속 시 자동으로 HTTPS로 리다이렉트됨
- 허용된 HTTP 방법은 GET, HEAD로 설정 -> 정적 리소스를 배포할 것이기 때문에 다른 HTTP Method를 허용하지 않아도 됨
- 캐시 키 및 원본 요청은 CachingOptimized를 선택 -> 대부분의 상황에서 적절한 캐시 정책을 바로 적용할 수 있음
- 보통 모든 엣지 로케이션에서 사용(최고의 성능)을 사용하면 되지만, 비용을 절약해야 하는 상황이거나 서비스 지역 타겟이 정해져 있을 때 적절한 항목을 선택하면 됨
- 기본값 루트 객체에 인덱스 페이지의 파일명을 입력
/
는 입력하면 안 됨
- React와 같은 SPA를 배포하는 상황이라면 Fallback Redirect 설정을 해주어야 함
rlatkdFlaskWebServerSg
ubuntu@ip-10-0-3-255:~$ sudo apt update
ubuntu@ip-10-0-3-255:~$ sudo apt -y upgrade
ubuntu@ip-10-0-3-255:~$ sudo apt install -y apache2
ubuntu@ip-10-0-3-255:~$ sudo systemctl status apache2
ubuntu@ip-10-0-3-255:~$ sudo systemctl status apache2
● apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2023-11-22 09:37:20 UTC; 8s ago
Docs: https://httpd.apache.org/docs/2.4/
Main PID: 14846 (apache2)
Tasks: 55 (limit: 1121)
Memory: 5.0M
CPU: 33ms
CGroup: /system.slice/apache2.service
├─14846 /usr/sbin/apache2 -k start
├─14848 /usr/sbin/apache2 -k start
└─14849 /usr/sbin/apache2 -k start
Nov 22 09:37:20 ip-10-0-3-255 systemd[1]: Starting The Apache HTTP Server...
Nov 22 09:37:20 ip-10-0-3-255 systemd[1]: Started The Apache HTTP Server.
ubuntu@ip-10-0-3-255:~$ sudo apt install -y php
ubuntu@ip-10-0-3-255:~$ sudo systemctl restart apache2
ubuntu@ip-10-0-3-255:~$ sudo systemctl status apache2
● apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2023-11-22 09:40:07 UTC; 3s ago
Docs: https://httpd.apache.org/docs/2.4/
Process: 21605 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS)
Main PID: 21609 (apache2)
Tasks: 6 (limit: 1121)
Memory: 10.0M
CPU: 47ms
CGroup: /system.slice/apache2.service
├─21609 /usr/sbin/apache2 -k start
├─21610 /usr/sbin/apache2 -k start
├─21611 /usr/sbin/apache2 -k start
├─21612 /usr/sbin/apache2 -k start
├─21613 /usr/sbin/apache2 -k start
└─21614 /usr/sbin/apache2 -k start
Nov 22 09:40:07 ip-10-0-3-255 systemd[1]: Starting The Apache HTTP Server...
Nov 22 09:40:07 ip-10-0-3-255 systemd[1]: Started The Apache HTTP Server.
ubuntu@ip-10-0-3-255:~$ cd /var/www/html/
ubuntu@ip-10-0-3-255:/var/www/html$ ls
index.html
ubuntu@ip-10-0-3-255:/var/www/html$ sudo rm -rf *
ubuntu@ip-10-0-3-255:/var/www/html$ ls
- Amazon EC2(Flask)는 Backend server를 포함하며 Bastion Host 역할을 함
-
배스천 호스트(Bation Host)는 내부 네트워크와 외부 네트워크 사이에 위치하는 게이트웨이
-
보안대책의 일환으로 사용되며, 내부 네트워크를 겨냥한 공격에 대해 방어하도록 설계됨
-
네트워크의 복잡도와 구성에 따라 다르지만, 단일 배스천 호스트 그 자체로서 방어를 할 수도 있으며, 또는 다른 방호 계층과 함께 대형 보안 시스템의 일부가 되기도 함
-
접근 제어 기능과 더불어 게이트웨이로서 가상 서버(Proxy Server)의 설치, 인증, 로그 등을 담당
-
그만큼 위험에 노출되는 경우가 많기 때문에, 배스천 호스트는 네트워크 보안상 가장 중요한 방화벽 호스트임
-
특히 내부 네트워크 전체의 보안을 담당하기 때문에 관리자의 감시 및 정기적인 점검이 뒷받침되어야 함
CREATE SCHEMA IF NOT EXISTS `auction` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci ;
USE `auction` ;
-- -----------------------------------------------------
-- Table `auction`.`user`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `auction`.`user` (
`id` VARCHAR(50) NOT NULL,
`phone` VARCHAR(50) NOT NULL,
`password` VARCHAR(50) NOT NULL,
`nickname` VARCHAR(50) NULL DEFAULT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_0900_ai_ci;
-- -----------------------------------------------------
-- Table `auction`.` history`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `auction`.`history` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` varchar(50) NOT NULL,
`item_id` int NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- -----------------------------------------------------
-- Table `auction`.`item`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `auction`.`item` (
`id` INT NOT NULL AUTO_INCREMENT,
`endTime` DATETIME NOT NULL,
`startTime` DATETIME NOT NULL,
`name` VARCHAR(100) NOT NULL,
`content` TEXT NULL DEFAULT NULL,
`price` DOUBLE NOT NULL,
`user_id` VARCHAR(50) NOT NULL,
`image` VARCHAR(200) NOT NULL,
PRIMARY KEY (`id`),
INDEX `fk_item_user_idx` (`user_id` ASC) VISIBLE,
CONSTRAINT `fk_item_user`
FOREIGN KEY (`user_id`)
REFERENCES `auction`.`user` (`id`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
AUTO_INCREMENT = 32
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_0900_ai_ci;
-- -----------------------------------------------------
-- Table `auction`.`prehistory`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `auction`.`prehistory` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` varchar(50) NOT NULL,
`item_id` int NOT NULL,
`endTime` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_prehistory_user1_idx` (`user_id`),
KEY `fk_prehistory_item1_idx` (`item_id`),
CONSTRAINT `fk_prehistory_item1` FOREIGN KEY (`item_id`) REFERENCES `item` (`id`),
CONSTRAINT `fk_prehistory_user1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
)
ENGINE = InnoDB
AUTO_INCREMENT = 6
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_0900_ai_ci;
CREATE USER 'user1'@'%' IDENTIFIED BY '1234';
GRANT ALL ON auction.* TO 'user1'@'%';
.\terraform>aws configure
AWS Access Key ID [****************QNIN]: ****
AWS Secret Access Key [****************5d04]: ****
Default region name [ap-northeast-2]:
Default output format [json]:
.\terraform>aws s3 ls
2023-11-23 17:11:34 backfirststep-bucket
2023-11-24 10:15:45 cicd-bucket-jgwow
2023-11-22 20:39:35 firststep-bucket
2023-11-22 11:57:41 project3-shyun-bucket
2023-11-22 19:02:59 rlatkd-flask-bucket
2023-11-22 14:36:01 rlatkd-react-bucket
.\terraform>terraform init
Initializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v5.26.0...
- Installed hashicorp/aws v5.26.0 (signed by HashiCorp)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
C:\aws> terraform apply
aws_instance.example: Refreshing state... [id=i-060ecf5b27718c689]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated
with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# aws_instance.example must be replaced
-/+ resource "aws_instance" "rlatkdWebServer" {
~ arn = "arn:aws:ec2:ap-northeast-2:561845507088:instance/i-086cae3329a3f7d75" -> (known after apply)
~ associate_public_ip_address = true -> (known after apply)
...
...
+ user_data = "67e34b406ab639a606a64fe06965b26bf8036a9c" # forces replacement
+ user_data_base64 = (known after apply)
~ user_data_replace_on_change = false -> true
~ vpc_security_group_ids = [
- "sg-0380b404f6530ca72",
] -> (known after apply)
# (5 unchanged attributes hidden)
- capacity_reservation_specification {
- capacity_reservation_preference = "open" -> null
}
...
...
- root_block_device {
- delete_on_termination = true -> null
- device_name = "/dev/xvda" -> null
- encrypted = false -> null
- iops = 3000 -> null
- tags = {} -> null
- throughput = 125 -> null
- volume_id = "vol-037350e565483e3a9" -> null
- volume_size = 8 -> null
- volume_type = "gp3" -> null
}
}
Plan: 1 to add, 0 to change, 1 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_instance.rlatkdWebServer: Destroying... [id=i-086cae3329a3f7d75]
aws_instance.rlatkdWebServer: Still destroying... [id=i-086cae3329a3f7d75, 10s elapsed]
aws_instance.rlatkdWebServer: Still destroying... [id=i-086cae3329a3f7d75, 20s elapsed]
aws_instance.rlatkdWebServer: Destruction complete after 30s
aws_instance.rlatkdWebServer: Creating...
aws_instance.rlatkdWebServer: Still creating... [10s elapsed]
aws_instance.rlatkdWebServer: Still creating... [20s elapsed]
aws_instance.rlatkdWebServer: Creation complete after 22s [id=i-086cae3329a3f7d75]
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
React 앱은 Amazon EC2가 아닌 Amazon S3에 정적 상태로 저장하기 때문에 AWS CodeDeploy가 필요하지 않음
./.github/workflows/deploy.yml
name: Deploy to Amazon S3 bucket
on:
push:
branches: [ "main" ]
env:
AWS_REGION: ap-northeast-2
S3_BUCKET_NAME: rlatkd-react-bucket
CLOUDFRONT_NAME: E28M3K5TF5L3PV
permissions:
contents: read
id-token: write
jobs:
build:
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cache node modules
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- if: steps.npm-cache.outputs.cache-hit == 'true'
run: echo 'npm cache hit!'
- if: steps.npm-cache.outputs.cache-hit != 'true'
run: echo 'npm cache missed!'
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: npm install
- name: Build
10000
run: npm run build
- name: Remove template files
run: rm -rf node_modules public src index.html package*
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: upload to S3
run: aws s3 sync build/ s3://${{ env.S3_BUCKET_NAME }} --acl public-read
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: CloudFront delete cache
uses: chetan/invalidate-cloudfront-action@v2
env:
DISTRIBUTION: ${{ env.CLOUDFRONT_NAME }}
PATHS: "/*"
AWS_REGION: ${{ env.AWS_REGION }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
./client/src/styles/Header.js
...
...
{
isLogin ? (<button :
(<button><Link to='/login'>테스트/회원가입</Link></button>)
}
...
...
rlatkdCodeDeployEC2Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": "*"
}
]
}
rlatkdEC2AccessS3Role
ubuntu@ip-10-0-3-255:/var/www/html$ sudo apt update
ubuntu@ip-10-0-3-255:/var/www/html$ sudo apt update
ubuntu@ip-10-0-3-255:/var/www/html$ sudo apt install ruby-full
ubuntu@ip-10-0-3-255:/var/www/html$ sudo apt install wget
ubuntu@ip-10-0-3-255:/var/www/html$ cd /home/ubuntu
ubuntu@ip-10-0-3-255:~$
ubuntu@ip-10-0-3-255:~$ wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
ubuntu@ip-10-0-3-255:~$ chmod +x ./install
ubuntu@ip-10-0-3-255:~$ sudo ./install auto
ubuntu@ip-10-0-3-255:~$ sudo service codedeploy-agent status
● codedeploy-agent.service - LSB: AWS CodeDeploy Host Agent
Loaded: loaded (/etc/init.d/codedeploy-agent; generated)
Active: active (running) since Wed 2023-11-22 09:48:20 UTC; 7s ago
Docs: man:systemd-sysv-generator(8)
Process: 22738 ExecStart=/etc/init.d/codedeploy-agent start (code=exited, status=0/SUCCESS)
Tasks: 2 (limit: 1121)
Memory: 57.4M
CPU: 1.085s
CGroup: /system.slice/codedeploy-agent.service
├─22744 "codedeploy-agent: master 22744" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" >
└─22746 "codedeploy-agent: InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller of >
Nov 22 09:48:20 ip-10-0-3-255 systemd[1]: Starting LSB: AWS CodeDeploy Host Agent...
Nov 22 09:48:20 ip-10-0-3-255 codedeploy-agent[22738]: Starting codedeploy-agent:
Nov 22 09:48:20 ip-10-0-3-255 systemd[1]: Started LSB: AWS CodeDeploy Host Agent.
...
...
CGroup: /system.slice/codedeploy-agent.service
├─22744 "codedeploy-agent: master 22744" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" >
여기 확인 >>> └─22746 "codedeploy-agent: InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller of >
...
...
rlatkdCodeDeployRole
애플리케이션
배포 그룹
./appspec.yml
version: 0.0
os: linux
files:
- source: /
destination: /home/ubuntu/ssgbay
hooks:
BeforeInstall:
- location: scripts/beforeInstall.sh
runas: root
AfterInstall:
- location: scripts/afterInstall.sh
runas: root
- location: scripts/runServer.sh
runas: ubuntu
./scripts/beforeInstall.sh
#!/bin/bash
var=$(ps -ef | grep 'python3 -u app.py' | grep -v 'grep')
pid=$(echo ${var} | cut -d " " -f2)
if [ -n "${pid}" ]
then
kill -9 ${pid}
echo ${pid} is terminated.
else
echo ${pid} is not running.
fi
rm -rf /home/ubuntu/ssgbay
mkdir /home/ubuntu/ssgbay
./scripts/afterInstall.sh
#!/bin/bash
cd /home/ubuntu/ssgbay
echo ">>> make static directory for upload images -----------------------"
mkdir resources
echo ">>> pip install ---------------------------------------------------"
pip install -r requirements.txt
echo ">>> cron settings -------------------------------------------------"
crontab -l | { cat; echo "* * * * * /usr/bin/python3 /home/ubuntu/ssgbay/historyUpdate.py >> /var/log/cron.log 2>&1"; } | crontab -
echo ">>> remove template files -----------------------------------------"
rm -rf appspec.yml requirements.txt
echo ">>> change owner to ubuntu ----------------------------------------"
chown -R ubuntu /home/ubuntu/ssgbay
./scripts/runServer.sh
#!/bin/bash
cd /home/ubuntu/ssgbay
echo ">>> run app -------------------------------------------------------"
cron
python3 -u app.py > /dev/null 2> /dev/null < /dev/null &
./.github/workflows/deploy.yml
name: Deploy to Amazon EC2
on:
push:
branches: [ "main" ]
env:
AWS_REGION: ap-northeast-2
S3_BUCKET_NAME: rlatkd-flask-bucket
CODE_DEPLOY_APPLICATION_NAME: rlatkdFlaskApp
CODE_DEPLOY_DEPLOY_GROUP_NAME: rlatkdFlaskDeployGroup
permissions:
contents: read
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Upload to AWS S3
run: |
aws deploy push \
--application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
--s3-location s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip \
--ignore-hidden-files \
--source .
- name: Deploy to AWS EC2 from S3
run: |
aws deploy create-deployment \
--application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
--deployment-config-name CodeDeployDefault.AllAtOnce \
--deployment-group-name ${{ env.CODE_DEPLOY_DEPLOY_GROUP_NAME }} \
--s3-location bucket=$S3_BUCKET_NAME,key=$GITHUB_SHA.zip,bundleType=zip
Warning
(11:5) autoprefixer: start value has mixed support, consider using flex-start instead
./src/styles/MainPage.module.css
... ... .cardContainer { display: flex; flex-wrap: wrap; justify-content: start; max-width: 1024px; min-width: 1024px; gap: 70px; } ... ...
- Webpack 구성 파일의 모듈 규칙 안에서 로더를 설정하여 작동하는데, justify-content 항목은 start 보다
flex-start
로 하는게 더 호환성이 좋다고 추천... ... .cardContainer { display: flex; flex-wrap: wrap; justify-content: flex-start; max-width: 1024px; min-width: 1024px; gap: 70px; } ... ...
./package.json
- 일일히
start
에서flex-start
로 변경하는 방법도 있지만 무시하고 진행하려면sourceMap
의 설정 값을true
로 하는 방법도 있음... ... { loader: "sass-loader", options: { sourceMap: true, }, }, ... ...
ESLint
-
ECMAScipt 코드에서 문제점을 검사하고 일부는 더 나은 코드로 정정하는 린트 도구
-
코드의 가독성을 높이고 잠재적인 오류와 버그를 제거해 단단한 코드를 만드는 목적
-
코드에서 검사하는 항목
- 포맷팅: 일관된 코드 스타일을 유지하도록 하고 개발자로 하여금 쉽게 읽히는 코드를 만들어줌
- 코드 품질: 애플리케이션의 잠재적인 오류나 버그를 예방
Line 160:15: Redundant alt attribute. Screen-readers already announce `img` tags as an image. You don’t need to use the words `image`, `photo,` or `picture` (or any specified custom words) in the alt prop jsx-a11y/img-redundant-alt
.src/pages/CreatePage.js
... ... {imagePreview && (<img className={styles.previewImage} src={imagePreview} alt="Selected Image" />)} ... ...
... ... {imagePreview && (<img className={styles.previewImage} src={imagePreview} alt="Selected" />)} ... ...
...
...
Line 34:22: Expected '===' and instead saw '==' eqeqeq
Line 38:20: Expected '===' and instead saw '==' eqeqeq
...
...
.src/pagess/DetailPage.js
... ... if (purchaseId == '') { alert('로그인 후 입찰 가능합니다. '); return; } ... ...
- 이중 등호
==
보단 삼중 등호===
을 사용하는 것을 추천
비교 종류 추상적 같음 비교 엄격한 같음 비교 해당하는 기호 이중 등호, 동등 연산자 삼중 등호, 일치 연산자 비교 방식 자동으로 형변환하여 같음을 비교함 형변환을 수해하지 않고 비교함 ... ... if (purchaseId === '') { alert('로그인 후 입찰 가능합니다. '); return; } ... ...
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-VTU4ZNI12/deployment-archive$ ls
app.py crontabFile historyUpdate.py package-lock.json requirements.txt scripts
appspec.yml database.py node_modules package.json resources
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-3L7DPAI12/deployment-archive$ python app.py
Command 'python' not found, did you mean:
command 'python3' from deb python3
command 'python' from deb python-is-python3
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-3L7DPAI12/deployment-archive$ python3 app.py
Traceback (most recent call last):
File "/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-3L7DPAI12/deployment-archive/app.py", line 1, in <module>
from flask import Flask, request, jsonify
ModuleNotFoundError: No module named 'flask'
c55d7/d-VTU4ZNI12/deployment-archive$ pip --version
Command 'pip' not found, but can be installed with:
sudo apt install python3-pip
ubuntu@ip-10-0-3-255:/$ sudo apt-get install python3-pip
ubuntu@ip-10-0-3-255:/$ pip --version
pip 22.0.2 from /usr/lib/python3/dist-packages/pip (python 3.10)
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-VTU4ZNI12/deployment-archive$ python3 app.py
Traceback (most recent call last):
File "/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-VTU4ZNI12/deployment-archive/app.py", line 5, in <module>
from flask_jwt_extended import JWTManager
File "/usr/local/lib/python3.10/dist-packages/flask_jwt_extended/__init__.py", line 1, in <module>
from .jwt_manager import JWTManager as JWTManager
File "/usr/local/lib/python3.10/dist-packages/flask_jwt_extended/jwt_manager.py", line 8, in <module>
from jwt import DecodeError
ImportError: cannot import name 'DecodeError' from 'jwt' (/usr/local/lib/python3.10/dist-packages/jwt/__init__.py)
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-VTU4ZNI12/deployment-archive$ pip install jwt
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: jwt in /usr/local/lib/python3.10/dist-packages (1.3.1)
Requirement already satisfied: cryptography!=3.4.0,>=3.1 in /usr/local/lib/python3.10/dist-packages (from jwt) (41.0.5)
Requirement already satisfied: cffi>=1.12 in /usr/local/lib/python3.10/dist-packages (from cryptography!=3.4.0,>=3.1->jwt) (1.16.0)
Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from cffi>=1.12->cryptography!=3.4.0,>=3.1->jwt) (2.21)
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-VTU4ZNI12/deployment-archive$ pip list
...
...
PyGObject 3.42.1
PyHamcrest 2.0.2
PyJWT 2.8.0
PyMySQL 1.1.0
pyOpenSSL 21.0.0
...
...
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-G5SGOXI12/deployment-archive$ sudo pip install PyJWT==v1.7.1
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-G5SGOXI12/deployment-archive$ python3 app.py
- Serving Flask app 'app'
- Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
- Running on all addresses (0.0.0.0)
- Running on http://127.0.0.1:5000
- Running on http://10.0.3.255:5000
Press CTRL+C to quit
ubuntu@ip-10-0-3-255:~$ sudo apt-get update
ubuntu@ip-10-0-3-255:~$ sudo apt-get install mysql-client
ubuntu@ip-10-0-3-255:~$ sudo mysql -h database-1.cyu7qnoubf3u.ap-northeast-2.rds.amazonaws.com -u rlatkdMySQL -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 33
Server version: 8.0.33 Source distribution
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 33
Server version: 8.0.33 Source distribution
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| auction |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| auction |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
mysql> use auction;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+-------------------+
| Tables_in_auction |
+-------------------+
| history |
| item |
| prehistory |
| user |
+-------------------+
4 rows in set (0.00 sec)
mysql> select * from history
-> ;
+----+---------+---------+
| id | user_id | item_id |
+----+---------+---------+
| 11 | 11 | 11 |
+----+---------+---------+
1 row in set (0.00 sec)
...
...
connectionString = {
'host': 'database-1.cyu7qnoubf3u.ap-northeast-2.rds.amazonaws.com',
'port': 3306,
'database': 'auction',
'user': 'rlatkdMySQL',
'password': '****',
'charset': 'utf8',
'cursorclass': pymysql.cursors.DictCursor
}
...
...
Mixed Content: The page at 'https://d3u6h8k7brrkx6.cloudfront.net/' xhr. js:256 was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://43.202.66.215:5000/?sor=date&keyword='.
This request has been blocked; the content must be served over HTTPS.
$ sudo apt install nginx
$ sudo service nginx start
$ wget https://dl.eff.org/certbot-auto
$ sudo snap install core
$ sudo snap refresh core
$ sudo apt remove certbot
$ sudo snap install --classic certbot
$ ln -s /snap/bin/certbot /usr/bin/certbot
$ sudo certbot --nginx
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Your existing certificate has been successfully renewed, and the new certificate
has been installed.
The new certificate covers the following domains: AWS CLOUDFRONT ENDPOINT # https가 설정된 도메인
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Subscribe to the EFF mailing list (email: woorimprog@gmail.com).
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/idu-market.shop/fullchain.pem # 공개키 경로
Your key file has been saved at:
/etc/letsencrypt/live/idu-market.shop/privkey.pem # 비밀키 경로
Your certificate will expire on 2021-08-15. To obtain a new or
tweaked version of this certificate in the future, simply run
certbot again with the "certonly" option. To non-interactively
renew *all* of your certificates, run "certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
# 443 포트로 접근시 ssl을 적용한 뒤 3000포트로 요청을 전달해주도록 하는 설정.
server {
server_name SSGBAY;
location / {
proxy_pass AWS CLOUDFRONT ENDPOINT;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/SSGBAY/fullchain.pem; # managed by Cert>
ssl_certificate_key /etc/letsencrypt/live/SSGBAY/privkey.pem; # managed by Cert>
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
# 80 포트로 접근시 443 포트로 리다이렉트 시켜주는 설정
server {
if ($host = SSGBAY) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name SSGBAY;
return 404; # managed by Certbot
}
-
certbot을 이용하여 ssl인증서를 발급할 경우 3개월 마다 갱신을 해줘야 함 -
$ certbot renew
-
인증서의 유효기간이 끝나가면 본인이 certbot을 통해 ssl인증서를 받아올 때 입력해 준 이메일로 알림이 옴
-
3개월 마다 자동 갱신을 하도록 해줄 수도 있음 - crontab 이용
$ [CRON 형식] /usr/bin/certbot renew --renew-hook="sudo systemctl restart apache2"
sudo vi /etc/systemd/system/caddy.service
[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target
[Service]
Type=notify
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
sudo vi /etc/caddy/Caddyfile
{
admin 0.0.0.0:2020
}
<EC2의 퍼블릭 IPv4 주소>.nip.io {
reverse_proxy localhost:8080 # 들어오는 요청을 8080포트로 포워딩
}
# 예시 :
10.100.100.100.nip.io {
reverse_proxy localhost:8080
}
sudo systemctl daemon-reload
sudo systemctl enable --now caddy
sudo systemctl status -l caddy
$ sudo systemctl status caddy.service
● caddy.service - Caddy
Loaded: loaded (/etc/systemd/system/caddy.service; enabled; vendor preset: disabled)
Active: active (running) since 화 2023-04-11 13:27:50 UTC; 5s ago
Docs: https://caddyserver.com/docs/
Main PID: 11243 (caddy)
CGroup: /system.slice/caddy.service
└─11243 /usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
2023/11/25 13:56:33.748 INFO using adjacent Caddyfile
2023/11/25 13:56:33.749 WARN Caddyfile input is not formatted; run the 'caddy fmt' command to fix inconsistencies {"adapter": "caddyfile", "file": "Caddyfile", "line": 2}
2023/11/25 13:56:33.749 INFO admin admin endpoint started {"address": "0.0.0.0:2020", "enforce_origin": false, "origins": ["//0.0.0.0:2020"]}
2023/11/25 13:56:33.750 WARN admin admin endpoint on open interface; host checking disabled {"address": "0.0.0.0:2020"}
2023/11/25 13:56:33.750 INFO http server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443}
2023/11/25 13:56:33.750 INFO http enabling automatic HTTP->HTTPS redirects {"server_name": "srv0"}
2023/11/25 13:56:33.751 INFO http enabling HTTP/3 listener {"addr": ":443"}
2023/11/25 13:56:33.751 INFO failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Receive-Buffer-Size for details.
2023/11/25 13:56:33.751 INFO http.log server running {"name": "srv0", "protocols": ["h1",
28BE
"h2", "h3"]}
2023/11/25 13:56:33.751 INFO http.log server running {"name": "remaining_auto_https_redirects", "protocols": ["h1", "h2", "h3"]}
2023/11/25 13:56:33.752 INFO http enabling automatic TLS certificate management {"domains": ["10.100.100.100.nip.io"]}
2023/11/25 13:56:33.752 INFO autosaved config (load with --resume flag) {"file": "/root/.config/caddy/autosave.json"}
2023/11/25 13:56:33.752 INFO serving initial configuration
2023/11/25 13:56:33.753 INFO tls cleaning storage unit {"description": "FileStorage:/root/.local/share/caddy"}
2023/11/25 13:56:33.754 INFO tls finished cleaning storage units
2023/11/25 13:56:33.754 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0xc000335490"}
Successfully started Caddy (pid=23624) - Caddy is running in the background
- POST요청을 했는데 500 internal server Error가 발생 → 백엔드 문제인거 같음
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-3XWE5BBQE/deployment-archive$ ps -ef | grep python3
root 398 1 0 Nov22 ? 00:00:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers
root 567 1 0 Nov22 ? 00:00:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
ubuntu 38514 1 0 23:12 ? 00:00:00 python3 -u app.py
ubuntu 38537 38323 0 23:14 pts/0 00:00:00 grep --color=auto python3
- Flask 서버는 현재 잘 작동되고 있음 (당연히 다른 서비스가 잘 동작하니 서버에 문제가 생긴 건 아님)
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-3XWE5BBQE/deployment-archive$ kill -9 38514
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-3XWE5BBQE/deployment-archive$ ps -ef | grep python3
root 398 1 0 Nov22 ? 00:00:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers
root 567 1 0 Nov22 ? 00:00:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
ubuntu 38547 38323 0 23:15 pts/0 00:00:00 grep --color=auto python3
- 정상적으로 종료됨
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-3XWE5BBQE/deployment-archive$ python3 app.py
- Serving Flask app 'app'
- Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
- Running on all addresses (0.0.0.0)
- Running on http://127.0.0.1:5000
- Running on http://10.0.3.255:5000
Press CTRL+C to quit
121.166.242.167 - - [23/Nov/2023 23:16:45] "GET /?sort=date&keyword= HTTP/1.1" 200 -
[Errno 2] No such file or directory: './resources/우영미1.JPEG'
121.166.242.167 - - [23/Nov/2023 23:17:14] "POST /create HTTP/1.1" 500 -
...
...
app = Flask(**name**, static_folder='./resources/')
UPLOAD_FOLDER = path.join('.', 'resources/')
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
...
...
@app.route('/create', methods=['POST'])
def create():
try:
file = request.files['itemImage']
filename = file.filename
itemName = request.form.get('itemName')
itemContent = request.form.get('itemContent')
itemPrice = request.form.get('itemPrice')
itemImage = filename
userId = request.form.get('userId')
endTime = request.form.get('endTime')
file.save(os.path.join(app.config['UPLOAD_FOLDER'], file.filename))
image_url = 'http://43.202.66.215:5000/resources/' + file.filename
print(image_url)
return database.addItemInfo( itemName, itemContent, itemPrice, image_url, endTime, userId)
except Exception as e:
print(e)
return jsonify({"message": "요청중 에러가 발생"}), 500, {'Content-Type': 'application/json'}
...
...
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-3XWE5BBQE/deployment-archive$ ls
app.py crontabFile historyUpdate.py package-lock.json requirements.txt
appspec.yml database.py node_modules package.json scripts
(venv) C:\Users\User\Desktop\project123\server\resources>touch .placeholder
- 정상적으로 commit됨
ubuntu@ip-10-0-3-255:/opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/d-BCL59RJ22/deployment-archive$ ls
app.py crontabFile historyUpdate.py package-lock.json requirements.txt
appspec.yml database.py node_modules package.json scripts
- AWS CodeDeploy는 Amazon S3에서 빌드 산출물을 압축 파일로 가져와서 배포해줌
- AWS CodeDeploy에는 빌드 기능이 없기 때문에 별도의 빌드 과정이 필요함
- AWS CodeDeploy가 시행되기 위해선 Amazon EC2의 CodeDeploy Agent가 반드시 실행중이어야함
ubuntu@ip-10-0-3-255:$ sudo service codedeploy-agent status
● codedeploy-agent.service - LSB: AWS CodeDeploy Host Agent
Loaded: loaded (/etc/init.d/codedeploy-agent; generated)
Active: active (running) since Wed 2023-11-22 10:32:17 UTC; 1 day 14h ago
Docs: man:systemd-sysv-generator(8)
Tasks: 4 (limit: 1121)
Memory: 91.5M
CPU: 29.000s
CGroup: /system.slice/codedeploy-agent.service
├─22869 "codedeploy-agent: master 22869" "" "" "" "" "" "" "" "" "" "" "" "">
└─22871 "codedeploy-agent: InstanceAgent::Plugins::CodeDeployPlugin::Command>
- 실제 Flask App 서비스가 작동하고 있는 WorkDirectory는
.server/scripts/runServer.sh
에 명시된 대로./home/ubuntu/ssgbay
였음
./server/scrpts/runServer.sh
#!/bin/bash
cd /home/ubuntu/ssgbay
echo ">>> run app -------------------------------------------------------"
cron
python3 -u app.py > /dev/null 2> /dev/null < /dev/null &
./opt/codedeploy-agent/deployment-root/2a2e556f-917b-4615-a1ff-97a1ce4c55d7/${DEPLOY_LATEST_DIRECTORY}/deployment-archive
는 Amazon S3에서 zip파일을 가져올 tmp 디렉터리였음
./server/scripts/afterInstall.sh
#!/bin/bash
cd /home/ubuntu/ssgbay
echo ">>> make static directory for upload images -----------------------"
mkdir resources
...
...
ubuntu@ip-10-0-3-255:~/ssgbay$ ls
**pycache** crontabFile historyUpdate.py package-lock.json resources
app.py database.py node_modules package.json scripts
Crontab: 정해 놓은 일정 시각이 되면 설정해둔 작업을 실행
- 경매글 쓰기에서 경매 만료 시간을 설정
- 다른 유저가 해당 상품을 입찰
- 경매 만료 시간까지 자신의 입찰가가 최고가이면 구매 확정이 되어 해당 상품의 입찰 내역을 구매내역에서 볼 수 있음
./server/scripts/afterInstall.sh
#!/bin/bash
cd /home/ubuntu/ssgbay
echo ">>> make static directory for upload images -----------------------"
mkdir resources
echo ">>> pip install ---------------------------------------------------"
pip install -r requirements.txt
echo ">>> remove template files -----------------------------------------"
rm -rf appspec.yml requirements.txt
echo ">>> change owner to ubuntu ----------------------------------------"
chown -R ubuntu /home/ubuntu/ssgbay
- 당연히 Crontab 관련 명시를 안 했으니 동작이 할리가 없음
./server/scripts/afterInstall.sh
#!/bin/bash
...
...
echo ">>> cron settings -------------------------------------------------"
crontab -l | { cat; echo "* * * * * /usr/bin/python3 /home/ubuntu/ssgbay/historyUpdate.py >> /var/log/cron.log 2>&1"; } | crontab -
...
...
./server/scripts/runServer.sh
#!/bin/bash
cd /home/ubuntu/ssgbay
echo ">>> run app -------------------------------------------------------"
cron
python3 -u app.py > /dev/null 2> /dev/null < /dev/null &
2023-11-24 am10:30 전
2023-11-24 am10:30 후
...
...
- name: Cache node modules ⇐ 캐시 액션 설치 및 설정 → 배포 시간 단축
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- if: steps.npm-cache.outputs.cache-hit == 'true' ⇐ 캐싱 여부를 출력
run: echo 'npm cache hit!'
- if: steps.npm-cache.outputs.cache-hit != 'true'
run: echo 'npm cache missed!'
- name: Install Dependencies ⇐ 캐시가 없거나 다른 경우에만 모듈 설치 → 배포 시간 단축
if: steps.cache.outputs.cache-hit != 'true'
run: npm install
- name: Build
run: npm run build
- name: Remove template files ⇐ 실행과 관련 없는 파일/디렉터리 삭제 → 배포 시간 단축
run: rm -rf node_modules public src index.html package*
...
...
- name: CloudFront delete cache ⇐ 캐시 무력화 설정 → 배포 시간 단축
uses: chetan/invalidate-cloudfront-action@v2
env:
DISTRIBUTION: ${{ env.CLOUDFRONT_NAME }}
PATHS: "/*"
AWS_REGION: ${{ env.AWS_REGION }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
-
기본적인 3계층 구조를 퍼블릭 클라우드로 배포해서 Docker & Kubernetes와는 색다르게 재밌었습니다.
-
또한 시연을 한 번에 성공한 것이 아닌 실패를 반복하며 구조들의 유기적인 흐름을 이해하는데 도움이 되었습니다.
-
그 중 가장 중요하다고 생각하는 보안과 연관된 설정(ex. 그룹, 액세스, 정책, 권한 등)들을 많이 배웠고 이렇게 실습 형식이 아닌, 실무에서 적용할 수 있도록 더 공부해야 할 것 같습니다.
-
모르는 것을 찾아볼 때 기존엔 구글링을 열심히 했지만 이번 기회 덕에 공식 문서를 자주 찾아봤고, 이를 통해 공식 문서에서 먼저 찾아보는 습관을 들였습니다.
-
프로젝트를 일찍 완료하고 다른 사람들과 공유하고 도와주며, 저와는 다른 환경에서의 배포에 대해 Trouble Shooting을 같이 하며 많은 시간을 할애했습니다.
-
이를 통해 정말 다양한 환경에서의 배포 과정에 대해 학습했으며, 일찍 완료했지만 다른 서비스들(ex. LB+ASG, EKS, GA를 이용한 Docker Image 생성, Lambda 등)을 시도하지 못 해 아쉽습니다.
-
그래도 다음 최종 프로젝트는 약 2달 간의 기간이 있기때문에 이번 기회에 기본기를 확실히 다져놓은 것 같아 기대가 됩니다.
-
Terraform을 이용해 코드로 내가 구상한 인프라가 자동으로 생성되는 것이 너무 신기하고 재밌었으며, GitHub Actions와 AWS CodeDeploy를 통해 배포 자동화를 함으로써 안 그래도 재밌는 공부 더욱더 재밌어졌습니다.
-
하루하루 지날 때마다 성장하고 있음을 느끼며 제 목표에 다다르는데 이제 시작이고, 앞으로의 내일들이 너무 기대가 됩니다.
-
개발 시 코딩 컨벤션 문서를 기반으로 lint 환경을 세팅하여 lint 에러가 발생할 때마다 왜 그런지 원인을 발견할 수 있도록 하는게 필요함
-
클린코드의 장점과 가독성이 좋은 코드의 장점을 66C3 려 조화로운 코드를 짜야함
-
AWS SAA를 공부하며 다양한 서비스를 알게 되었는데, AWS CloudFront 말고도 다른 걸 시도해봤어야함
-
Amazon Route 53을 이용해 레코드를 연결할 생각해야함
-
정책이나 역할 등의 권한을 해당하는 내용은 다 허용한다 했는데 명확히 제약 조건을 거는 것이 중요함
-
Amazon DynamoDB에 Terraform lock 파일 연동시킬 생각해야함
-
GitHub Actions를 이용해서 Docker image 생성할 생각해야함
-
보안 상의 이유로 허점을 좀 더 깊게 공부해서 명확하게 구분하고 파악할 수 있어야함
-
실시간 모니터링이나 로그 분석에 대한 생각을 좀 더 해야함 (CloudTrail, CloudWatch 등)
-
조금 더 사용자의 관점에서 깊게 생각해봐야함
-
SQS, SNS, Fargate, QuickSight, KMS, Backup 등 생소한 AWS 서비스들에 대해 이해를 높여야함
-
Redis, Jenkins, ArgoCD, ElasticSearch, Apache Kafka 등 생소한 외부 서비스들에 대한 이해를 높여야함
-
어떤 서비스가 어떤 역할을 하는지에 대해 끊임없이 공부해서 명확히 구분하고 적용할 생각을 해야함