'CLI'에 해당하는 글 5건

파일 mime-type 체크

Daily/Prog 2020. 5. 14. 18:26



얼마전 s3 에 업로드된 상당량의 이미지 mime-type 이 octet-stream 으로 올라가 있는 것을 확인했다. 또 그 파일들은 모두 확장자가 대문자인 것도 확인했다.


String mimeType = Files.probeContentType(path);


위 부분에서 대문자 확장자 파일들에 대한 처리가 정상적으로 되지 않아 null 을 반환한 것이 문제였다. 확장자로 mimeType 을 얻어오는 과정에서 발생할 예외들을 미리 예상하여 처리할 수도 있지만, 업로드시 파일에서 직접 mimeType 을 확인할 수도 있다. Apache 의  Tika 라이브러리를 사용해 봤다.


compile group: 'org.apache.tika', name: 'tika-core', version: '1.24'

...

String mimeType = new Tika().detect(inputStream);


tika-parsers 는 용량이 어마무시하다. parser 가 꼭 필요한게 아니라면 core 만 받자.


그리고 기존에 s3 에 octet-stream 타입으로 업로드된 이미지 파일들은 aws-cli 로 배치처리 하여 image/jpeg 으로 변경하였다.


> aws s3 cp \

 s3://bucket/path \

 s3://bucket/path \

 --exclude "*" \

 --include "*.JPG" \

 --acl public-read \

 --no-guess-mime-type \

 --content-type "image/jpeg" \

 --metadata-directive "REPLACE" \

 --recursive

 --profile myprofile


아쉽게도 include 에 지정한 패턴이 대소문자를 구분하지 못해서 시간이 꽤 걸렸음...




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

ECS with gradle

Server/AWS 2018. 8. 28. 23:51

개발 중에는 Java + Gradle 프로젝트에서 결과물을 확인하기 위해, ssh 플러그인을 사용해 개발 서버에 배포하고 있다. 실서버 ECS 배포를 위해 이미지를 만들고 ECR 에 푸시하고 Task 를 배포하는 플러그인이 있나 열심히 검색해 보았으나, 음... 생각만큼 지원이 덜 되어 있는거 같아 그냥 AWS Cli 명령으로 도배했다. 난 포기했지만 생각 있으면 써보시길...


'com.bmuschko.docker-remote-api'

'com.patdouble.awsecr'


build.gradle 로 처리하려는 것들을 나열해 봤다.


  1. 인스턴스 수량 증가
  2. Docker 이미지 빌드
  3. 기존 ECR latest 이미지 태그 변경 -> backup
  4. 이미지 ECR 로 푸시
  5. 서비스 업데이트 (배포)
  6. 인스턴스 수량 감소


이 모든걸 원클릭으로 끝내버리고 싶었는데, 배포 완료 시점을 알아야 했고 그로 인한 서브 작업들이 꼴도 보기 싫어서 그만 두었다. (꽤 지긋지긋해졌다) 저 얼마되지도 않는 작업을 실행하는데 필요한 오라질 도구가 참 많다. Docker, AWS Cli, ECS-Cli, PowerShell, ... 물론 Linux 환경이라면 PowerShell 하나 정도는 줄일 수 있겠지만 그러자고 Linux 환경을 하나 더 구축하는 것 역시 오라질이다. 그리고 ECR 이미지 태그를 변경하는 것 역시 포기했다. PowerShell 에서 AWSPowerShell 을 설치해야 되는데 에러 투성이다. 포기하고 backup 은 push 를 두 번 하는 방향으로; AWS Cli 로 통합하지 못하고 AWS Cli, ECS-Cli, PowerShell 을 다 깔 수 밖에 없게끔 만들어 놓은 이유가 참으로 궁금하다. docker 가 PowerShell 을 사용한 원죄가 있긴 하지만... 그렇게 따지면 윈도우를 만든... ㅡ.ㅡ;


아무튼 내가 구축하려는 구성은 기본 인스턴스 2 대, 배포시 4 대, 배포후 다시 2 대.

Cluster, Service, Task, ECR 등은 이미 콘솔에 생성되어 있다. (구성 내용 생략)


그리하여 실행할 gradle Task 는 3 개 정도 되겠다.

1,2,3,4 번을 묶어 backup 이 어찌될지 모르니 푸시까지 하나 (createImageNpushToECR), 5 번 배포 하나(ECSDeploy), 6 번 인스턴스 감소 하나(ECSInstanceDown).


* build.gradle


ext {
    clusterName = 'clusterName'
    serviceName = 'serviceName'
    taskName = 'taskName'
    stackName = 'EC2ContainerService-now-web'
    accountId = '8707500123456'
    region = 'ap-northeast-1'
    tagName = '870750012345.dkr.ecr.ap-northeast-1.amazonaws.com/web:latest'
    instanceMinCnt = 2
    instanceMaxCnt = 4
    getInstanceCnt = 0
}
 
task createImageNpushToECR() {
    group = 'docker'
    dependsOn war
    doFirst {
        exec { commandLine 'cmd''/c''aws ecr get-login --no-include-email --profile profileName > temp.cmd' }
        exec { commandLine 'cmd''/c''call temp.cmd' }
        exec { commandLine 'cmd''/c''del temp.cmd' }
    }
    doLast {
        exec { commandLine 'cmd''/c''docker build -t '+tags+' .' }
        exec { commandLine 'docker''push', tags }
    }
}
 
task ECSDeploy {
    group = 'docker'
    doLast {
        exec { commandLine 'cmd''/c''aws ecs update-service --force-new-deployment --profile profileName --cluster ' + clusterName + '  --service ' + serviceName + ' --task-definition ' + taskName }
    }
}
 
task ECSInstanceCnt {
    group = 'docker'
    doLast {
        new ByteArrayOutputStream().withStream { cnt ->
            exec {
                commandLine 'cmd''/c''aws ecs list-container-instances --cluster ' + clusterName + ' | findstr /R /C:"[' + accountId + ']" | find /c /v ""'
                standardOutput = cnt
            }
            getInstanceCnt = cnt.toString().toInteger()
        }
        println '# Current Web Instance Cnt : ' + getInstanceCnt
    }
}
 
task ECSInstanceUp {
    group = 'docker'
    dependsOn ECSInstanceCnt
    doLast {
        if (instanceMaxCnt > getInstanceCnt) {
            exec { commandLine 'cmd''/c''aws ecs update-service --cluster ' + clusterName + '  --service ' + serviceName + ' --deployment-configuration minimumHealthyPercent=50,maximumPercent=200' }
            exec { commandLine 'cmd''/c''ecs-cli configure --cluster ' + clusterName + ' --default-launch-type EC2 --region ' + region + ' --cfn-stack-name ' + stackName + ' --config-name ' + clusterName }
            exec { commandLine 'cmd''/c''ecs-cli scale --capability-iam --size ' + instanceMaxCnt + ' --cluster ' + clusterName + ' --aws-profile profileName' }
        }
    }
}
 
task ECSInstanceDown {
    group = 'docker'
    dependsOn ECSInstanceCnt
    doLast {
        if (instanceMinCnt < getInstanceCnt) {
            exec { commandLine 'cmd''/c''aws ecs update-service --cluster ' + clusterName + '  --service ' + serviceName + ' --deployment-configuration minimumHealthyPercent=100,maximumPercent=200' }
            exec { commandLine 'cmd''/c''ecs-cli configure --cluster ' + clusterName + ' --default-launch-type EC2 --region ' + region + ' --cfn-stack-name ' +  stackName + ' --config-name ' + clusterName }
            exec { commandLine 'cmd''/c''ecs-cli scale --capability-iam --size ' + instanceMinCnt + ' --cluster ' + clusterName + ' --aws-profile profileName' }
        }
    }
}
cs


대충 이렇다. 지금 딱 필요한 만큼만 꾸역꾸역 만들어 놓긴 했는데... 맘엔 안들지만 그래도 그냥 쓸란다.

간단하게 설명하자면...

  • createImageNpushToECR : war 파일 만들고 ECR 에 로그인 후 Docker 이미지 만들고 푸시.
  • ECSDeploy : Service 업데이트로 최신 이미지(latest) 배포
  • ECSInstanceCnt : 현재 Cluster 의 인스턴스 수량 (2개 설정)
  • ECSInstanceUp : 인스턴스 증가시킬 수량인 4 개 보다 작으면 4 개로 증설
  • ECSInstanceDown : 인스턴스 감소시킬 수량인 2 개 보다 크면 2 개로 감소


ECR 로그인은 gradle 소스에 있고 ECS-Cli 자격 증명 역시 aws profile 로 통합했다. AWS Cli 를 위한 자격 증명은 잘 등록해 보자... aws configure...


명령어도 윈도우 명령어로 바꿔 넣느라 삽질 좀 했다. 후...

개발에만 집중할 수 있게 해준다더니, 빡이쳐서 개발을 할 수가 없다. 아오...




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

AWS ECR

Server/AWS 2018. 8. 15. 00:33

ECS 를 시작하기 전에 가장 먼저 어플리케이션을 이미지로 만들어 ECR(Elastic Container Registry) 에 등록을 해 보자. ECR 에 이미지를 등록하는 것은 ECS 와 연계되는 부분이 거의 없으므로 ECS 를 몰라도 상관없다. 이미지 등록에만 집중하자.

 

ECS 를 몰라도 상관없다고 말했지만, 꼭 집고 넘어가야 할게 있다. ㅜ ECS 를 사용할 때 사용자가 선택할 수 있는 두 가지 선택지가 있다. 하나는 인스턴스로서 EC2 를 사용할지 Fargate 를 사용할지이고 (이를 시작 유형이라고 함), 또 하나는 Docker Registry 를 공개용(public) 으로 구성할지 비공개용(private) 으로 구성할지 이다. Fargate 라는 것은 컨테이너를 위한 EC2 등의 인스턴스를 필요로 하지 않고 컨테이너 자체를 배포하는 아마존의 기술이다. 지금은 몰라도 된다. 하지만 알고 싶다면... EC2 에서 돌아가던 것이 EC2 없이도 어디선가 돌아간다 라고 생각하면 쉽다; 그만큼 EC2 등의 인스턴스를 관리하는 노력이 줄어드니까 더 좋다고도 볼 수 있다. EC2 를 컨트롤 하는 것 처럼 정밀한 제어는 힘들겠지만. 아무튼 좋아보이니 비싸기도 하다. EC2 시작 유형을 사용해보면 Fargate 설정은 훨씬 더 쉬우므로 EC2 시작 유형 기반으로 설명할 것이다. 아마도 대부분이 실전에서는 private 저장소를 사용하게 될텐데, 혹시라도 public 저장소를 사용하게 되면 EC2 인스턴스 유형을 사용할 수 없다. 즉 EC2 인스턴스 유형은 private 저장소만 지원한다. 이를 유념하도록 하고... ECS 에서 Docker Registry 는 ECR 말고도 아마 거의 다 지원할 것이다. Docker Hub, self-hosted registry 등...

 

여기서는 아마존 패밀리인 ECR 을 사용해 보도록 하겠다.

 

 

1. Docker 이미지 생성

 

docker 이미지를 생성하려면 Docker 를 설치하고 데몬을 실행시켜 docker cli 를 사용할 수 있어야 한다. (여기까지는 알아서 잘 해보자 ㅜ)

그리고 이미지 설정 파일인 dockerfile 을 만들어 필요에 맞게 구성한다.

나는 다음과 같이 tomcat 에서 구동하는 war 파일에 ssl 통신이 가능하도록 이미지화 하는 dockerfile 을 만들었다. (이것도 본인 필요에 맞게 알아서 잘 해보자;)

 

$ vi dockerfile
FROM tomcat:8.0-jre8-alpine
RUN ["rm""-rf""/usr/local/tomcat/webapps/ROOT"]
COPY ["./keystore""./server.xml""./web.xml""/usr/local/tomcat/conf/"]
COPY ./build/libs/WEB-0.0.1-SNAPSHOT.war /usr/local/tomcat/webapps/ROOT.war
cs

 

dockerfile 기반으로 hello-world 라는 이미지를 생성하고 확인한다.

 

$ docker build -t hello-world .
$ docker images --filter reference=hello-world
$ docker run -p 8080:8080 hello-world
cs

 

해당 포트의 반응이 없을 경우, 서버나 VirtualBox VM 에서 컨테이너 포트에 인바운드 트래픽이 허용되어 있는지 체크한다. 

 

 

2. ECR 에 저장소 생성

 

이미지가 정상적으로 생성되었다면, AWS Docker Registry 인 ECR 에 푸시를 해보자.

그 전에 ECR 에 이미지를 푸시하기 위해서는 AWS cli 가 반드시 필요하다. 로그인 및 푸시 명령이 AWS cli 으로만 가능하다. 알아서 cli 를 설치한다. ㅜ

먼저 콘솔이나 cli 로 ECR 에 특정 이름의 저장소를 생성한다.

cli 를 사용할 때는 root 계정을 사용하지 말고 ECS 용 IAM 계정을 새로 생성하고 profile 에 등록하는 편이 낫다. 해당 key 로 profile 에 자격증명 및 리전 등록하는 것은 생략.

 

$ aws ecr create-repository --repository-name hello-world-repo
{
    "repository": {
        "registryId": "aws_account_id",
        "repositoryName": "hello-world-repo",
        "repositoryArn": "arn:aws:ecr:us-east-1:aws_account_id:repository/hello-world-repo",
        "createdAt": 1505337806.0,
        "repositoryUri": "aws_account_id.dkr.ecr.us-east-1.amazonaws.com/hello-world-repo"
    }
}
cs

 

콘솔을 이용하던 cli 를 이용하던 저장소를 생성하고 나면 이미지를 푸시할 주소인 repositoryUri 를 확인할 수 있다.

repositoryUri 에는 12 자리 숫자의 aws_account_id, 리전, 저장소 이름이 포함되어 있다.

 

 

3. ECR 로 이미지 푸시

 

저장소를 생성했으면 이미지를 푸시하면 되는데, 그러기 위해서는 푸시할 이미지를 repositoryUri 값으로 태그 지정해야 한다.

 

$ docker tag hello-world aws_account_id.dkr.ecr.us-east-1.amazonaws.com/hello-world-repo
cs

 

태그 지정을 마쳤으면 푸시를 하기 전에 ECR 에 로그인 과정을 거쳐야 한다.(참 번거롭다.ㅜ)

 

$ aws ecr get-login --no-include-email

// aws cli v2+
$ aws ecr get-login-password --region xxxx (--profile xxx) | docker login --username AWS --password-stdin xxx(accountId).dkr.ecr.xxx(region).amazonaws.com
cs

 

위 명령을 입력하면 로그인에 필요한 명령어를 포함한 12시간 짜리 토큰이 발급된다.

 

docker login -u AWS -p ...base64 encoding token...very...long...  https://aws_account_id.dkr.ecr.us-east-1.amazonaws.com
cs

 

이와 같은 형태인데 이 부분을 그대로 복붙했다가는 프로세스 목록(ps) 에 토큰이 다 노출되게 되므로 패스워드 옵션(-p) 전까지만 입력하고 대화형 방식으로 토큰을 입력하던지 eval 명령을 사용한다.

 

$ eval $(aws ecr get-login --no-include-email)
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
Login Succeeded
cs

 

마지막으로 repositoryUri 태그가 달린 이미지를 푸시한다.

 

$ docker push aws_account_id.dkr.ecr.us-east-1.amazonaws.com/hello-world
cs

 

ECS - Repositories 에서 푸시된 이미지 확인.

 

 

나중에 어떤 식으로든 자동화를 해야겠지만 일단 이렇게 번거로운 과정을 거치면 비로소 ECR 에 이미지를 푸시할 수 있게 된다. 수정된 이미지를 다시 푸시할 경우에 토큰이 만료됐다면 위 로그인 과정을 다시 거쳐야 한다.

그럭저럭 쓸만함...

 

 


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

Multiple credentials

Server/AWS 2018. 7. 27. 00:11

IAM 에서 사용자에게 모든 role 을 부여하지 않고 필요에 맞게 사용자를 추가하여 role 을 부여했다면, cli 사용시 여러 사용자의 자격 증명을 로컬 파일에 저장하고 서비스에 맞게 자격 증명을 선택하여 사용할 수도 있다. 여러 자격 증명의 구분을 프로필 이름으로 할 수 있도록 프로필 이름을 명시한다.



Named profiles


~/.aws/credentials
 
[default]
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
 
[user2]
aws_access_key_id=AKIAI44QH8DHBEXAMPLE
aws_secret_access_key=je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY
 
~/.aws/config
 
[default]
region=us-west-2
output=json
 
[profile user2]
region=us-east-1
output=text
cs


보다시피 credentials 파일과 config 파일의 [profile name] 형식이 다름에 유의 한다.

이렇게 수동으로 작성해도 되고, aws configure 명령을 사용하여 profile 을 추가해도 된다.


$ aws configure --profile user2
AWS Access Key ID [None]: AKIAI44QH8DHBEXAMPLE
AWS Secret Access Key [None]: je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY
Default region name [None]: us-east-1
Default output format [None]: text
cs


이렇게 여러 자격 증명이 등록되었다면 실제 명령에 --profile user2 라고 추가하면 되고,

계속해서 해당 프로필을 사용한다면 아래처럼 환경 변수로 등록할 수 있다.


$ export AWS_PROFILE=user2
cs


현재 자격 증명 확인


$ aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                    user2           manual    --profile
access_key     ****************MPLE shared-credentials-file
secret_key     ****************EKEY shared-credentials-file
    region                us-east-1      config-file    ~/.aws/config
cs




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

AWS CLI

Server/AWS 2018. 7. 26. 14:41

AWS CLI(Command Line Interface) 는 AWS 서비스와 상호 작용하는 명령을 제공하는 오픈 소스 도구이다.

Linux 나 Windows 등의 원하는 터미널 프로그램에서 AWS Management 콘솔이 제공한 모든 기능을 사용할 수 있다.

콘솔이 제공하는 모든 기능을 사용할 수 있지만, 반드시 cli 를 사용해야만 하는 경우도 있으니 참고하자.

 

 

설치

 

Linux 든 Windows 든 AWS cli 배포 방식이 pip 이므로, python 이 먼저 설치되어야 한다.

윈도우라 하더라도 최신 버전을 필요로 하는 기능들이 많아 간편한 업데이트를 위해 pip 설치를 하는 것이 좋다.

윈도우 기준으로 python 사이트에서 python 을 설치 한 후 path 를 추가하고 아래와 같이 AWS cli 를 설치하고 업데이트 할 수 있다.

 

$ pip install awscli
$ pip install awscli --upgrade --user
cs

 

 

자격 증명 등록

 

대부분의 경우 자격 증명(credential) 을 필요로 하므로, 자격 증명을 로컬 파일에 저장해 놓을 수 있다.

 

~/.aws/credentials
 
[default]
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
 
~/.aws/config
 
[default]
region=us-west-2
output=json
cs

 

이렇게 사용자 디렉토리에 두개의 파일로 나누어 access_key, secret_key, region, output 등을 수동으로 설정할 수도 있고, aws configure 명령으로 설정할 수도 있다. 또한 여러 profile 을 관리할 때는 --profile name 옵션을 사용하여 등록하고 선택하여 사용할 수 있다.

 

$ aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: us-west-2
Default output format [None]: ENTER

$ aws configure --profile user2
...

$ aws configure list-profiles
default
user2

# default profile을 변경
$ export AWS_DEFAULT_PROFILE=user2 (linux)
$ set AWS_DEFAULT_PROFILE=user2 (windows)
cs

 

 


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,