Loading the catalog…
Loading the catalog…
문제 상황: 계정 A의 프리티어 기간이 종료되었다. 그래서 다른 프리티어 계정 B로 서버를 이전하고자한다. 해결 방법: 계정 A에서 계정 B로 EC2를 옮기자. 현재 서버 구조: RDS 비용 절감을 위해 8월에 이미 RDS를 삭제하고, ec2에 mysql을 설치해서 DB 데이터를 이전하였다. 따라서 현재 하나의 ec2 서버 위에 spring, mysql, ngnix가 모두 한꺼번에 있는 구조이다. (최소한의 비용을 위해) 1. AWS 서버 이전 AWS EC2를 이전하는 가장 간단한 방법은 AWS에서 제공해주는 AMI로 복제하는 것이다. AMI(Amazon Machine Images)는 EC2 인스턴스를 설정하고 부팅하는데 필요한 소프트웨어를 제공하는 이미지이다. AMI 이미지로 EC2 인스턴스를 만들면 동일한 세팅으로 EC2를 여러 개 만들 수 있기 때문에 서버 이전이나 복제에 주로 사용된다. 이때는 리전, 운영체제 등의 조건이 같아야한다. 출처: AWS 공식 문서 - Amazon Machine Images in Amazon EC2 2. 계정 A : 서버 이미지 생성 및 공유 2.1 기존 EC2의 AMI 생성 1) AMI 생성 기존 계정 A에서 AMI를 생성한다. EC2 → 인스턴스 → 기존 인스턴스 선택 → 작업 → 이미지 및 템플릿 → 이미지 생성 2) 옵션 선택 DB가 같은 EC2에서 실행 중이라면 기본 재부팅 방식으로 생성하는 것이 안전하다. No reboot은 파일시스템 정합성이 보장되지 않을 수 있어서 재부팅 항목도 체크해주었다. AMI 이름 입력하기 가능하면 재부팅 옵션 선택 3) 생성 완료 그러면 AMI 이미지가 생성된다. EC2 → AMI에서 Available 상태 확인하면 최종 생성이 된것이다. 이제 계정 A에서 ec2의 AMI 생성이 끝났다. 4) AMI 복사 후 서버 체크 (추가) AMI 복사 후 인스턴스가 재부팅되면서 원래 서버가 제대로 올라왔는지 꼭 확인한다. 만약 서버가 내려갔으면 우선 수동 실행으로라도 서버를 동작 시켜둔다. 나도 아래와 같이 오류가 발생해서 서버가 잠깐 내려갔었다. [트러블 슈팅] 문제 상황: 인스턴스 재부팅으로 deploy.sh가 실행됐는데, 로그 쓰는 동작 권한이 막혀서 배포에 실패하고 운영서버가 내려갔다. 해결 방법 : 아래와 같이 권한을 ubuntu로 바꿔서 해결했다. $ sudo chown ubuntu:ubuntu \ /home/ubuntu/backend/app/app.log \ /home/ubuntu/backend/app/error.log 1.2 AMI 비공개 공유 1) 권한 편집 계정 A에서 계정 B로 AMI 비공개 공유해야한다. 이를 위해 계정 A에서 방금 생성한 AMI 권한을 편집한다. EC2 → AMI → 생성한 AMI 선택 → 작업 → AMI 권한 편집 AMI 가용성을 비공개(Private)로 유지 공유 계정에 계정 B의 12자리 계정 ID 추가 공개 AMI로 바꾸지 말고 특정 계정에만 공유하도록 한다.❗️ 출처: AWS 공식 문서 - AWS 계정 간 AMI 공유 방법 2) 공유 id 입력 AMI 공유 칸에 계정 B의 id를 넣는다. 계정 B의 AWS 계정 ID 확인 B 계정에서 오른쪽 위 계정 메뉴를 누르면 12자리 AWS 계정 ID를 확인할 수 있다. ex. 123456789012 ❗️ IAM 사용자 ID가 아니라 AWS 계정 ID가 필요하다. * 3) 공유 확인 * 아래와 같이 AMI 공유 계정에 계정 B가 추가되면, 계정 B에서 해당 AMI를 다운받을 수 있다. 이제 계정 A의 AMI를 계정 B로 공유가 완료되었다. 2. 계정 B : AMI 복사 및 인스턴스 생성 2.1 공유된 AMI를 복사 1) AMI 확인 이제 계정 B로 로그인하고, 기존 AMI와 같은 리전 선택한다. 아까 프라이빗으로 공유했으니, 필터에서 프라이빗 이미지를 누르면 계정 A에서 공유한 AMI 이미지가 뜬다. EC2 → AMI → Private images → 계정 A에서 공유한 AMI 확인 * 2) AMI 복사 * 공유받은 AMI를 그대로 사용할 수도 있지만, 계정 A와 완전히 분리하려면 계정 B에서 복사하는 것이 좋다. 공유된 AMI 선택 → 작업 → AMI 복사 3) AMI 복사 옵션 선택 AMI는 리전 단위이므로 양쪽 콘솔의 리전이 서울이라면 모두 ap-northeast-2여한다. 대상 리전 선택 새 AMI 이름 입력 [트러블 슈팅] 문제: 계정 B에서 AMI 접근 권한이 없어서 발생한 오류이다. 해결: 계정 A에서 공유 계정에 계정 B의 id가 제대로 들어갔는지 확인하고, 없다면 추가한다. EC2 → AMI → AMI 선택 → 스토리지 → 스냅샷 선택 → 권한 수정 → 계정 B의 id 추가 4) 복사 확인 복사를 실행하고 복사본이 Available이 될 때까지 기다린다. 사용 가능이 뜨면 성공이다! 계정 B가 소유한 독립적인 AMI와 EBS 스냅샷이 만들어졌기 때문에, 이후 계정 A에서 공유를 해제하거나 원본 AMI를 삭제해도 계정 B의 복사본은 유지된다. 이제 계정 A의 AMI를 복사한 계정 B의 AMI가 생성이 끝났다. 스냅샷 저장 비용 나는 완료기간이 없는 스냅샷이기 때문에 스냅샷 저장 비용이 들지 않지만, 그래도 혹시 몰라서 이전 이후 스냅샷을 삭제하였다. *시간 기반 스냅샷 복사에 대해서는 비용이 발생할 수 있다. - AWS AMI 복사 문서 2.2 복사한 AMI로 인스턴스 생성 이제 계정 B에서 복사한 AMI로 EC2 인스턴스를 생성해야한다. AMI를 선택하고 인스턴스 시작을 누른다. EC2 인스턴스 생성할 때와 동일하게 해주면된다. 이미지에서는 복사를 뜬 AMI를 선택해준다. 키페어를 생성해서 다운 받고, 보안 그룹도 설정해준다. 이때, 개발 편의성을 위한다면 0.0.0.0/0을 사용하지만, 보안을 위한다면 내 ip 만 허용하도록 한다. 스토리지 구성까지 마치면 인스턴스를 생성할 수 있다. 3. 계정 B: EC2 환경 세팅 이제 인스턴스 복제는 끝났지만, 계정 B의 환경에 맞춰서 변경해줘야하는 값들이 있다. 3.1 env의 값 변경 AMI 복제를 했기 때문에 이전 계정 A에서의 환경변수 값이 그대로 일 것이다. 따라서, 계정 B EC2에 .env 파일에 있는 환경변수 값을 바뀐 환경에 맞게 변경해줘야한다. $ sudo nano .env $ source .env 3.2 ngnix 및 https 설정 https 인증서를 재발급 받고, ngnix도 맞춰서 수정해줘야한다. 지금 port switching 방법을 사용하기 때문에, 포트 번호 8081과 8082를 번갈아가면서 사용하고 있다. Nginx 설정을 배포할 때마다 config에서 포트 번호를 직접 수정하기보다는, upstream 설정을 별도 파일로 분리해서 링크를 전환하는 방식이 깔끔하다. 1) 포트별 config 파일 생성 먼저 설정파일을 따로 생성해준다. $ sudo mkdir -p /etc/nginx/upstreams 포트 8081번 config $ sudo tee /etc/nginx/upstreams/zzicgo-8081.conf > /dev/null <<'EOF' upstream zzicgo_backend { server 127.0.0.1:8081; keepalive 32; } EOF 포트 8082번 config $ sudo tee /etc/nginx/upstreams/zzicgo-8082.conf > /dev/null <<'EOF' upstream zzicgo_backend { server 127.0.0.1:8082; keepalive 32; } EOF 2) config 적용 지금 8081 포트에서 실행중이라면 해당 config를 적용하도록 아래의 명령어를 입력한다. $ sudo ln -sfn \ /etc/nginx/upstreams/zzicgo-8081.conf \ /etc/nginx/conf.d/zzicgo-upstream.conf 3) ngnix 설정 수정 핵심은 ngnix 설정에서 proxy_pass를 특정 포트에 고정하지 않고 ringout_backend라는 upstream 이름을 사용하며, Health Check 성공 후 upstream 링크를 8081과 8082 사이에서 전환하는 것이다. 1. Nginx → 8081 2. 새 Spring을 8082에서 실행 3. 8082 Health Check 성공 4. upstream 링크를 8082 설정으로 변경 5. nginx -t 6. Nginx reload 7. 기존 8081 Spring 종료 ngnix 설정 파일에서 proxy_pass 에 http://zzicgo_backend 로 수정한다. server { listen 80 default_server; listen [::]:80 default_server; server_name _; location / { proxy_pass http://zzicgo_backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } 현재 Config 확인 명령어 아래 명령어로 현재 읽히고 있는 config를 확인할 수 있다. $ readlink -f /etc/nginx/conf.d/zzicgo-upstream.conf 결과로 "/etc/nginx/upstreams/zzicgo-8081.conf"로 나온다면 8081 config를 읽고 있는것이다. 4) ngnix 변경 반영 ngnix 변경을 반영하고 서버가 연결되었는지 확인한다. # Nginx 문법 검사 $ sudo nginx -t # 변경 사항 반영 $ sudo systemctl reload nginx # 서버로 연결되는지 확인 $ curl -IL http://api.example.com/swagger-ui.html 5) Https 인증서 발급 도 허용 시켜둔다. 두 도메인에 HTTPS 인증서를 발급하고, Nginx에 자동으로 적용하는 명령어이다. sudo certbot --nginx \ -d zzicgo.com \ -d api.zzicgo.com 3.3 deploy.sh 수정** 배포 파일에서도 Spring 실행 옵션에 --server.address=127.0.0.1을 추가한다. 이를 통해 Spring은 EC2 내부의 127.0.0.1:8081 또는 127.0.0.1:8082에서만 요청을 받는다. 기존에는 외부에서 http://{EC2_IP}:{포트}/swagger-ui/index.html로 Spring에 직접 접근할 수 있었지만, 변경 후에는 8081·8082 포트로 직접 접근할 수 없다. 외부 요청은 DNS를 통해 EC2의 Nginx로 전달되고, Nginx가 현재 활성화된 Spring 포트로 요청을 프록시한다. 따라서 사용자는 https://{도메인}/swagger-ui/index.html로 접속하게 된다. AWS EC2 인바운드 규칙 수정 (추가) 추가로 EC2 보안 그룹의 인바운드 규칙에서도 8081·8082 포트를 제거하여, 외부에서 Spring에 직접 접근하지 못하도록 한다. Spring은 127.0.0.1:8081 또는 127.0.0.1:8082에서 실행되기 때문에 EC2 내부에서는 Health Check가 가능하지만, 외부 요청은 80·443 포트로 Nginx에 들어온 뒤 현재 활성화된 Spring 포트로 전달된다. 이를 통해 외부에서는 Spring에 직접 접근하지 않고 Nginx를 통해서만 접근하도록 제한한다. 4. S3 버킷 이전하기 기존 프로젝트에서 S3를 사용했었다. AMI로는 S3가 복사되지 않기 때문에, 계정 B에서 새로 S3를 만들고 데이터를 옮겨와야한다. 1) 계정 B에서 새로운 S3 버킷 생성 2) 계정 A의 데이터를 계정 B로 이전 추가로 계정 A에 있던 S3 데이터를 계정 B의 S3로 그대로 옮기기 위해서는 아래와 같은 과정을 거칠것이다. 계정 A 기존 버킷 → 계정 B EC2의 IAM Role에 읽기 권한 부여 → 계정 B 신규 버킷으로 sync → Spring의 버킷명 변경 → 최종 전환 직전에 한 번 더 sync 4.1 계정 B: S3 버킷 생성 1) S3 버킷 생성 [ZzicGo] AWS S3 사용하여 사진 업로드 기능 구현 (Spring) 를 참고해서 그대로 만들면 된다. 이때는 그냥 네임스페이스를 바로 입력했는데, 지금은 "계정 리전 네임스페이스"라는 선택지가 생겼다. AWS 공식 문서 - 범용 버킷의 네임스페이스 계정 리전 네임스페이스는 "접두사 + 계정 ID + 리전 + -an" 조합으로 S3 버킷의 이름을 생성하기 때문에 다른 계정이 동일한 이름으로 버킷 생성이 불가능하다. 따라서 AWS에서는 이 방식을 권장하고 있다. S3 버킷 정책 Public 버킷 정책에 아래처럼 public 읽기 허용을 넣고, 퍼블릭 액세스 차단도 해제해주면 aws s3에서 객체 URL로 바로 접근이 가능하다. { "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadProfileImages", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::{❗️계정-B-버킷명}/profile/*" } ] } 2) S3 IAM 사용자 생성 ZzicGo사진-업로드-화면-S3-연동#iam-사용자 를 참고해서 계정 B에서도 iam 사용자를 만든다. 그리고 그 사용자의 액세스 키값을 EC2 .env에 갱신하는 거까지 완료하면 된다. # 예시: AWS_IAM_ACCESS_KEY=... AWS_IAM_SECRET_KEY=... AWS_S3_BUCKET_NAME=... 여기서 중간 체크로 s3 사진을 한번 업로드 해보면 성공한다. 계정 B의 서버에서 계정 B의 S3로 이미지 업로드는 문제 없다는 뜻이다. 여기서 생길 수 있는 문제가 가용성이다. 만약 계정 b에서 업로드 했을 때, 계정 a에서도 업로드를 했어서 id가 겹친다면? 이거는 문제가 생길 수 있다. 여기서 다루지는 않지만, 추후 생각해볼 문제이다. 4.2 계정 B: Ec2 IAM Role 생성 1) Ec2 IAM Role 생성 IAM 사용자와 IAM Role은 다른 개념이다. IAM 사용자는 s3 업로드를 앞으로 담당할 것이고, 계정 B의 역할은 이번 s3 이전에서만 임시로 사용하고 삭제할 것이다. 계정 B IAM 사용자 → 앞으로 Spring의 S3 업로드 담당 계정 B EC2 IAM Role → 이번 S3 이전에만 임시 사용 EC2에서 IAM 역할을 생성한다. IAM -> 액세스 관리 -> 역할 -> 역할 생성 2) 인라인 정책 이제 인라인 정책을 작성해준다. --delete 옵션을 사용하지 않고 애플리케이션에서도 객체를 삭제하지 않는다면 ManageDestinationObjects에서 "s3:DeleteObject"는 제외해도 된다. 나는 제외하도록 하겠다. { "Version": "2012-10-17", "Statement": [ { "Sid": "ListSourceBucket", "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:GetBucketLocation" ], "Resource": "arn:aws:s3:::{❗️계정-A-버킷명}" }, { "Sid": "ReadSourceObjects", "Effect": "Allow", "Action": [ "s3:GetObject" ], "Resource": "arn:aws:s3:::{❗️계정-A-버킷명}/*" }, { "Sid": "ListDestinationBucket", "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:GetBucketLocation" ], "Resource": "arn:aws:s3:::{❗️계정-B-버킷명}" }, { "Sid": "ManageDestinationObjects", "Effect": "Allow", "Action": [ "s3:GetObject", "s3:PutObject" ], "Resource": "arn:aws:s3:::{❗️계정-B-버킷명}/*" } ] } 3) 검토 마지막으로 이름을 지정하고 검토 후 역할을 생성한다. 4) Iam Role과 Ec2 연결 이제 이 역할을 ec2랑 연결해야한다. 인스턴스 -> 작업 -> 보안 -> IAM 역할 수정 4.3 계정 A: 접근 권한 수정 1) 계정 A에서 계정 B의 role 접근 허용 계정 A에서도 위의 역할이 접근하는 것을 허용해야 한다. 계정 A의 기존 버킷 정책에도 계정 B Role을 허용해야하기 떄문에 아래처럼 추가했다. { "Version": "2012-10-17", "Statement": [ { "Sid": "AllowAccountBRoleToList", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::{❗️계정-B-ID:role}/{❗️계정-B-role명}" }, "Action": [ "s3:ListBucket", "s3:GetBucketLocation" ], "Resource": "arn:aws:s3:::{❗️계정-A-버킷명}" }, { "Sid": "AllowAccountBRoleToRead", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::{❗️계정-B-ID:role}/{❗️계정-B-role명}" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::{❗️계정-A-버킷명}/*" } ] } 4.4 S3 버킷 데이터 이전하기 이제 계정 A의 데이터 복사해서 계정 B로 전송할 것이다. 1) aws cli 설치 먼저, 계정 B ec2에 접속하고, aws cli를 설치해준다. $ sudo snap install aws-cli --classic 그리고 아래의 명령어를 쳤을 때, 방금 만든 ec2 Iam role이 제대로 떠야한다. 만약 로그인이 필요하다고 뜬다면, ec2와 역할이 제대로 연결되었는지 확인해라. $ aws sts get-caller-identity 2) 터미널 변수값 입력 먼저 터미널에 변수 값을 입력한다. 이 값은 ssh가 끝나면 사라지는 임시값이다. SOURCE_BUCKET="실제-계정-A-버킷명" DEST_BUCKET="실제-계정-B-버킷명" 값이 잘 들어갔는지 확인한다. echo "$SOURCE_BUCKET" echo "$DEST_BUCKET" 3) 버킷 접근 확인 계정 A 버킷에 접근이 가능한지 확인한다. aws s3 ls "s3://$SOURCE_BUCKET" [트러블 슈팅] 문제: 아래처럼 차단되었다는 메세지가 떴다. 해결: 계정 A에서 네번쨰 체크박스를 해제해주었다. 그리고 계정 B 버킷 접근도 확인한다. aws s3 ls "s3://$DEST_BUCKET" 4) Dry Run으로 복사 대상 확인 먼저 dry run을 통해서 서로 데이터를 주고 받을 수 있는 상태인지 확인한다. aws s3 sync \ "s3://$SOURCE_BUCKET" \ "s3://$DEST_BUCKET" \ --source-region ap-northeast-2 \ --region ap-northeast-2 \ --dryrun 5) 실제 복사 Dry Run 결과에 문제가 없다면 --dryrun만 제거한다. 이제 실제 복사가 될 것이다. (--delete는 추가하지 않는다. 계정 B 버킷에만 존재하는 파일이 삭제될 수 있기 때문이다.) aws s3 sync \ "s3://$SOURCE_BUCKET" \ "s3://$DEST_BUCKET" \ --source-region ap-northeast-2 \ --region ap-northeast-2 6) 객체 수와 전체 크기 비교 제대로 복사가 되었는지 확인하기 위해서 객체 수와 크기를 비교한다. 계정 A 원본 버킷 확인 aws s3 ls "s3://$SOURCE_BUCKET" \ --recursive \ --summarize \ --human-readable 계정 B 대상 버킷 확인 aws s3 ls "s3://$DEST_BUCKET" \ --recursive \ --summarize \ --human-readable 각 명령의 마지막에 다음
What RADAR observed and classified to build this opportunity. It is what the source published, not a verification that the offer is still active.
[ZzicGo] AWS 계정 A에서 B로 EC2 옮기기. 문제 상황: 계정 A의 프리티어 기간이 종료되었다. 그래서 다른 프리티어 계정 B로 서버를 이전하고자한다. 해결 방법: 계정 A에서 계정 B로 EC2를 옮기자. 현재 서버 구조: RDS 비용 절감을 위해 8월에 이미 RDS를 삭제하고, ec2에 mysql을 설치해서 DB 데이터를 이전하였다. 따라서 현재 하나의 ec2 서버 위에 spring, mysql, ngnix가 모두 한꺼번에 있는 구조이다. (최소한의 비용을 위해) 1. AWS 서버 이전 AWS EC2를 이전하는 가장 간단한 방법은 AWS에서 제공해주는 AMI로 복제하는 것이다. AMI(Amazon Machine Images)는 EC2 인스턴스를 설정하고 부팅하는데 필요한 소프트웨어를 제공하는…
Open source