본문으로 건너뛰기

"aws" 태그로 연결된 7개 게시물개의 게시물이 있습니다.

모든 태그 보기

Window에서 aws cli 사용시 bad interperter 오류

· 약 1분

git bash에서 aws cli 명령어를 실행시에 c:\Program Files... bad interpreter 오류가 나오면서 실행이 안 될 때는 다음과 같이 하면 된다.

~/.bash_profile 에 aws alias를 추가한다.

$ vi ~/.bash_profile
# aws script 경로를 강제로 지정한다
alias aws='python "C:\Program Files\Python\Scripts\aws"'
# 추가 후 저장
$ source ~/.bash_profile

Cloudfront 캐시 지우기

· 약 1분

클라우드프론트로 static website hosting 을 할 경우에 삭제된 s3 의 파일이 노출되는 경우가 있다. 캐싱처리되어서 보이는 현상인데 다음과 같이 해결하면 된다.

Invalidate 기능을 사용해서 캐시를 지워버리자. Cloudfront Distributions > ID 클릭 > Invalidations 에서 Create Invalidation 버튼을 누른다.

image from hexo

Object Paths에 캐시를 지울 경로를 입력한다. 예를 들어 assets/js 하위의 소스 맵 파일만 지운다면 다음과 같다.

/assets/js/*.map

입력 후에 Invalidate 버튼을 누르면 5~10 분 안에 리스트의 Status 가 Completed 로 변하고 기존 캐시가 사라진다.

AWS Cli S3 파일 업로드

· 약 1분

웹 상에서 파일을 업로드할 때 md5 checksum 오류가 발생해 파일이 전체가 다 안 올라가는 경우도 있고, 세션이 만료되 올라가는 도중에 끊기기도 하는 것 같다.

업로드 할 bucket 의 이름을 조회한다.

$ aws s3 ls

앞이 복사할 폴더이고 뒤가 파일이 복사될 s3 bucket 경로이다.

$ aws s3 cp ./ s3://{bucket_name}/{path}/ --recursive --exclude "*.mp4" --acl public-read

mp4 를 제외한 폴더의 모든 하위 파일들을 public-read 권한으로 업로드했다.

옵션 확인

cli docs에서 디테일한 옵션은 확인 가능하다.

Alpine Linux AWS Cli 설치

· 약 1분

차례대로 실행만 해주면 된다.

# python 설치 안 된 경우
# $ apt install python

# pip 설치
$ curl -O https://bootstrap.pypa.io/get-pip.py
$ python get-pip.py --user

# PATH 등록
$ export PATH=~/.local/bin:$PATH
# aws cli 설치
$ pip install awscli --upgrade --user

$ aws --version

AWS CodeCommit 사용하기

· 약 5분

AWS 에서 제공하는 Cloud Git Repository 인 CodeCommit 으로 소스코드를 관리해보자.

공식 문서가 아주 잘 되어있다. 문서를 보고 시작해도 된다.

IAM 유저 생성

IAM 에서 유저를 만든 뒤에 AWSCodeCommitFullAccess 권한을 추가한다.

키 파일 업로드

ssh 키를 생성하고 Public Key 파일(id_rsa.pub)을 해당 유저의 Security credentials 메뉴에서 업로드한다. 키가 등록되면 SSH key ID가 보이는데 메모해 놓자.

config

사용할 유저의 ssh config 를 설정해줘야한다. User 에 들어가는 값은 위에서 적어놓은 SSH key ID 값이다.

$ vi ~/.ssh/config

# 아래 내용을 맨 위에 넣어주자.
Host git-codecommit.*.amazonaws.com
User EXAMPLEEXAMPLEEXAMPLE
IdentityFile ~/.ssh/id_rsa

# 저장한 뒤 권한을 바꿔준다.
chmod 600 ~/.ssh/config

테스트

설정이 완료된 후에 서울리젼으로 ssh 연결을 시도해보자.

$ ssh git-codecommit.ap-northeast-2.amazonaws.com

# 다음과 같은 메세지가 리턴되면 성공이다.
You have successfully authenticated over SSH. You can use Git to interact with AWS CodeCommit. Interactive shells are not supported.Connection to git-codecommit.
ap-northeast-2.amazonaws.com closed by remote host.
Connection to git-codecommit.ap-northeast-2.amazonaws.com closed.

연동

이제 AWS CodeCommit 과 내 소스를 연결시켜보자.

# 이미 존재하는 프로젝트의 경우
$ git remote remove origin
$ git remote add origin ssh://git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/레파지토리명

# 처음 시작하는 경우
$ git clone ssh://git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/레파지토리명

# 권한이 없거나 ssh 계정을 물어볼 때
# origin의 path 앞에 SSH key ID를 추가하자
$ git remote add origin ssh://EXAMPLEEXAMPLEEXAMPLE@git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/레파지토리명

git pull origin master시에 정상적으로 가져오는 걸 확인할 수 있다.

ssh 연동이 잘 되지 않을시

메뉴얼대로 따라해도 연동이 안될 때는 당황하지 말고 IAM > Users > Security credentials에서 HTTPS Git credentials for AWS CodeCommit를 만들어주고 CodeCommit Repository 연결을 http로 하면 된다.

Webhook

Github, Bitbucket 와 달리 Webhook 설정하는 법이 조금은 복잡하다. (GCP 의 Pub/Sub 와 비슷한 느낌)

CodeDeploy 서비스를 사용하면 쉬워질 것 같은데, 그럼 CodePipeline 도 쓰고 싶을 것 같고 CI 세팅을 해야되고 다음 기회에

Lambda

람다는 웹(URL)으로 호출할 수 있는 Javascript function 이다.

설정

먼저 Lambda > 함수 > 함수생성 > 새로 작성 메뉴에서 webhook 이란 이름의 함수를 생성한다. 트리거 구성 메뉴에서 CodeCommit 을 선택하고 입력 폼을 잘 채워주자.

image from hexo

기존 브랜치로 푸시, master 브랜치를 선택했다. 사용자 지정데이터에는 webhook 을 걸 URL 경로를 넣어준다. (예: https://yourdomain.com/webhook)

소스

이미 세팅된 함수를 사용하자.

"use strict";

const url = require("url");
const https = require("https");

exports.handler = (event, context, callback) => {
let webhook_url = event.Records[0].customData;

if (!webhook_url) {
let error = new Error("Web-hook URL not provided as custom data.");
callback(error);
} else {
console.log("POST web-hook to " + webhook_url);
let options = url.parse(webhook_url);
options["method"] = "POST";

const req = https.request(options, (res) => {
let body = "";
console.log("Status:", res.statusCode);
console.log("Headers:", JSON.stringify(res.headers));
res.setEncoding("utf8");
res.on("data", (chunk) => (body += chunk));
res.on("end", () => {
console.log("Successfully triggered web-hook.");
// If we know it's JSON, parse it.
if (res.headers["content-type"] === "application/json") {
body = JSON.parse(body);
}
callback(null, body);
});
});

req.on("error", callback);
req.end();
}
};

https 커넥션이 아닌 경우 http 모듈을 사용해서 request 를 보내면 될 것 같다.

등록 후엔 CodeCommit > 트리거 > webhook > 트리거 테스트를 진행하면 정상적으로 호출이 된다.

로그

호출 로그는 CloudWatch > 로그에서 생성한 Lambda 명으로 확인할 수 있다.

로그 스트림이 설정되지 않았을 경우엔 Lambda > 구성 > 기존 역할에 표시된 역할(Rule)이 해당 Lambda 함수를 잡고 있는지 확인해야한다. IAM > Rules > 해당 룰 > Permissions에서 Show policy를 누르면 Resource 속성에서 확인할 수 있고 다르다면 제대로 연결시켜주면 된다.

여담

AWS Korea week in review에 소개되었다.

AWS ECS 부수기

· 약 6분

ECS 는 서울 리젼이 아직 없어서 그런가, 구글링해도 사용할만한 데이터가 너무 적었다. (기초 설명은 잘 되있다. 하지만 Hello World Application 을 올리려고 ECS 를 쓰는 건 아니니까..)

Cluster

Amazon ECS 클러스터는 작업을 배치할 수 있는 컨테이너 인스턴스의 논리적 그룹화입니다. 이 공식 설명을 보고 Cluster 에 대한 감을 잡기가 쉽지 않았다.

  • 간단히하면 Docker Container 를 올리는 EC2 Instance 이다.
  • K8S 의 그 클러스터이다.

Task

  • Task 는 작업이라고 번역되며, 하나의 Task Definition JSON 은 하나의 Docker-compose YAML 이라고 보자.

Container Definition

  • 배포되는 각 컨테이너의 정의
  • 파드의 개념

Task Definition

  • 컨테이너의 집합인 Task의 정의
  • 파드의 개념

Service

Amazon ECS 는 단일 ECS 클러스터에서 작업 정의에 지정된 수("원하는 개수")의 인스턴스를 동시에 실행 및 관리할 수 있게 해줍니다. 어떤 이유로 작업이 실패 또는 중지되는 경우 Amazon ECS 서비스 스케줄러가 작업 정의의 다른 인스턴스를 시작하여 이를 대체하고 서비스의 원하는 작업 수를 유지합니다.

  • Task 를 자동으로 관리할 수 있게 하는 기능, LB 나 Auto Scaling 모두 여기서 적용이 된다.
  • 롤링 업데이트 시에 배포 및 오토 스케일링을 담당한다.
  • K8S의 서비스, 디플로이먼트, 레플리카세트의 역할

Repository

AWS Docker 레지스트리 서비스로 AWS Private DockerHub 라고 보자.

네트워크 모드

모드내용
default네트워크 모드 기본값으로 bridge와 같음
awsvpcAWS에서만 제공되는 네트워크 모드 (ENI가 Task 자체 VPC의 IP 주소할당)
bridgeDockerContainer를 호스트와 같은 네트워크에 배치해 라우팅 없이 컨테이너 접근 가능
hostTask가 배치되는 호스트의 네트워크를 공유하는 모드 (Fargate 사용 불가)
noneTask에 속한 컨테이너의 외부 접근이 불가능하고 포트 매핑 사용불가

볼륨 생성

-v 또는 --volume 으로 Host 의 폴더를 Mount 하는 기능이 꼭 필요한데, 설정 창에선 찾기가 너무 힘들었다. ECS 에서는 작업 정의 생성 시에 하단에 볼륨 추가 를 꼭 먼저 클릭해 볼륨부터 추가해야한다.

image from hexo 이름엔 --name 옵션 사용하듯이 닉네임을 넣고 소스 경로엔 Host directory 경로를 넣자.

추가가 되면 컨테이너 추가 시에 탑재 지점 메뉴의 소스 볼륨 select box 에서 선택할 수 있다.

image from hexo

이 짓을 하는 것보단 공식 문서의 Task Definition JSON Parameter 를 보고 JSON 으로 때려박는게 편하다.

예시 JSON 은 아래와 같다. (3306 과 3307 을 열고 Host 의 Data 폴더를 Mount 하는 기본 구성의 MariaDB Image)

mariadb
{
"requiresAttributes": [
{
"value": null,
"name": "com.amazonaws.ecs.capability.docker-remote-api.1.21",
"targetId": null,
"targetType": null
}
],
"taskDefinitionArn": "your task definition arn",
"networkMode": "bridge",
"status": "ACTIVE",
"revision": 3,
"taskRoleArn": null,
"containerDefinitions": [
{
"volumesFrom": [],
"memory": null,
"extraHosts": null,
"dnsServers": null,
"disableNetworking": null,
"dnsSearchDomains": null,
"portMappings": [
{
"hostPort": 3306,
"containerPort": 3306,
"protocol": "tcp"
},
{
"hostPort": 3307,
"containerPort": 3307,
"protocol": "tcp"
}
],
"hostname": null,
"essential": true,
"entryPoint": null,
"mountPoints": [
{
"containerPath": "/var/lib/mysql",
"sourceVolume": "dbdata",
"readOnly": null
}
],
"name": "maria",
"ulimits": null,
"dockerSecurityOptions": null,
"environment": [
{
"name": "MYSQL_DATABASE",
"value": "db"
},
{
"name": "MYSQL_PASSWORD",
"value": "db_pw"
},
{
"name": "MYSQL_ROOT_PASSWORD",
"value": "root_pw"
},
{
"name": "MYSQL_USER",
"value": "db_user"
}
],
"links": null,
"workingDirectory": null,
"readonlyRootFilesystem": false,
"image": "mariadb:latest",
"command": [
"mysqld",
"--character-set-server=utf8",
"--collation-server=utf8_general_ci"
],
"user": null,
"dockerLabels": null,
"logConfiguration": null,
"cpu": 0,
"privileged": null,
"memoryReservation": 500
}
],
"placementConstraints": [],
"volumes": [
{
"host": {
"sourcePath": "/ecs/dbdata"
},
"name": "dbdata"
}
],
"family": "mariadb"
}

고민

Container 를 Task 별로 생성해야하는데, 그럼 Task JSON 에서 link 옵션을 연결할 수가 없다. 이 경우엔 어떻게 Task Definition 을 짜야되나? EC2 에 접근해서 매번 link 를 생성해서 다시 올려야되나?

이 부분을 해결하기 위해선 ecs-task-kite를 사용하거나 VPC 를 구성해 수동으로 연결해 주는 방법 밖에 없다.

쉬운 방법으로 가자면 DB 는 (모든 컨테이너가 하나의 데이터를 바라봐야하는) RDSElastiCache처럼 AWS 의 서비스 사용하고 VPC 를 구성해 Backend, Frontend 단의 서버만 ECS Task 를 만들어서 가변적으로 돌리는 게 좋아보인다.

물론 동기화를 할 수도 있는데... 삽질할 시간에 더 잘 나온 포스팅을 기다려본다.

여담

그냥 모니터링 컨테이너 하나 더 띄우고, HAProxy 컨테이너 올리고 EC2 에 다 때려박고 싶다.

AWS Korea week in review에 소개되었다.

AWS 용어 정리

· 약 2분

AWS의 생태계에 들어가기 위해선 먼저 용어에 익숙해져야 될 것 같았다. 사용법은 쉬운데.. 약어가 처음 접하는 사람에게 조금 부담스러웠다.

서비스명약어설명
Elastic Compute CloudEC2클라우드 서버
EC2 Container ServiceECSDocker 컨테이너 서버
Elastic Load BalancingELB트래픽, 부하 분산 서비스
Lambda-클라우드 Function
Scale Up-인스턴스 물리용량 증가
Scale Out-인스턴스 복제
Auto Scaling-인스턴스 Scale 자동화
Route 53-DNS 서비스
Virtual Private CloudVPC내부망 구축 서비스
Relational Database ServiceRDSRDBMS 구축 서비스
DynamoDB-NoSQL 구축 서비스
Simple Storage ServiceS3데이터 스토리지 서비스 (파일서버)
CloudFront-CDN 서비스
Glacier-저렴한 스토리지 서비스 (주로 백업용)
Elastic Block StoreEBSEC2의 가상 하드디스크
Identity and Access ManagementIAM인증, 권한 부여
CloudWatch-AWS 리소스 모니터링
Elastic BeanstalkEBPaaS
LightSail-저렴한 EC2 (VPS)

여담

전체적으로 GCP보다 용어가 직관적이지 않은 느낌 (App Engine, Compute Engine을 보면 얼마나 멋진가)이였는데, 풀어 놓고 적어보니 GCP도 AE, CE 이렇게 적으면 못 알아 먹었겠구나.