aws escのecs_params.yml の設定

AWS ECS のタスク定義で使うもの。(docker-composeの形式ではサポートしていないものが多いので)

下記を定義しておく。

version: 1
task_definition:
  ecs_network_mode: string
  task_role_arn: string
  task_execution_role: string
  task_size:
    cpu_limit: string
    mem_limit: string
  services:
    <service_name>:
      essential: boolean
      cpu_shares: integer
      mem_limit: string
      mem_reservation: string
      healthcheck:
        test: ["CMD", "curl -f http://localhost"]
        interval: string
        timeout: string
        retries: integer
        start_period: string 
run_params:
  network_configuration:
    awsvpc_configuration:
      subnets: 
        - subnet_id1 
        - subnet_id2
      security_groups: 
        - secgroup_id1
        - secgroup_id2
      assign_public_ip: ENABLED

下記のような感じでファイルを指定すれば読み込んでくれる

$ ecs-cli --ecs-params ${ecs_params.yml} 

spring webfluxでfile upload

SpringBoot webfluxでは、ファイルアップロードはMultiPartで取得できないので、探す。
PartFileというのがよかったでこちらで実験する。

ソースはこちら

Javaはこちら

package net.ksasaki.springboot.example.controller;

import org.springframework.http.MediaType;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import reactor.core.publisher.Mono;

import java.io.File;

@Controller
@RequestMapping("")
public class SampleController {

    @RequestMapping("")
    public String index() {
        return "index";
    }

    @ResponseBody
    @PostMapping(value = "/form", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Mono form(@RequestPart("part") FilePart part) {

        File file = new File(part.filename());
        part.transferTo(file);

        return Mono.empty();
    }
}

HTMLはこちら

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="/form" enctype="multipart/form-data" method="post">
    <input type="file" name="parts">
    <button type="submit">送信</button>
</form>
</body>
</html>

無事取得できたので、メモ。

AWS fargateで Task failed ELB health checks in (elb elb-name) がでた際には…

自分が携わってるサービスではaws fargateでデフォルトで設定してると発生する。
そのときの、対策メモ

fargateのスピンアップは遅い(自分のアプリでは)

fargateはコンテナの起動後から、すぐにELBが負荷分散のチェックが入るようで、デフォルトの設定だとすぐにタイムアウトして、Task failed ELB health checks in (elb elb-name)これを投げる。なんか、AWSでよくあるセキュリティグループとかの設定がー…とか思うんだけど、一番よくあるのは、このケース。
fargateの設定の中に、ヘルスチェックの猶予期間があるけど、これはデフォルトで120秒くらいにはしておこうと思う…
ターゲットグループの方でチェックしてもいいけど、アプリ切り替えとかしたときに、そっちの設定変更するときとか大変だし。

アベイラビリティゾーンの設定が…

よくプライベートセグメントとパブリックセグメントでわけてたりするんですけど、設定間違ってパブリックにしたりしてて、ELBが期待してるセグメントと違うことがあった。

他にもあったら追記します

nginxのupstreamのnameは_-とか使えない

ちょっとした社内向けのマイクロサービスしてると1つのnginxでいろんなところに飛ばす必要がでてきてしまい…
スネークケースとかケバブケースでnginx.confを書こうとしたらエラーになったのでメモ


upstream app_lb { server app.local }

この設定はNG

upstream applb {
     server app.local 
}

こっちはOK

nginxの設定のキー名によく_がでてくるから使えるかと思ったら使えなかった
ざざざっと書いたあとでエラーになったので、あせる

ちなみにエラーにはなるのだが、定義されてないので、使えないっていうのがさらに時間を溶かしていった

ログインシェルの変更

jenkinsなどで使いたいときがあるので、メモ

$ sudo chsh jenkins

これで使いたいshellを入れればOK

SpringBootアプリをjibでDocker化する

Google製のJavaをdocker化してくれるアプリでSpringBootのデモアプリをDocker化する

buildscript {
    ext {
        springBootVersion = '2.0.3.RELEASE'
    }
    repositories {
        mavenCentral()
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath "gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:0.9.8"
    }
}

group = 'net.kosasaki.example'
version = '0.0.1-SNAPSHOT'

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'com.google.cloud.tools.jib'

dependencies {
        compile('org.springframework.boot:spring-boot-starter-webflux')
        compile('org.springframework.boot:spring-boot-starter-thymeleaf')
        compileOnly('org.projectlombok:lombok:1.18.0')
        compile 'mysql:mysql-connector-java:6.0.6'  
}

jib {
        from {
                image = 'adoptopenjdk/openjdk8:alpine-slim'
        }
        to {
                image = 'sample/jib-demo-app'
        }
        container {
                jvmFlags = ['-Xms512m', '-Xdebug']
                mainClass = 'net.kosasaki.example.WebApplication'
                args = []
                ports = ['8080/tcp']
                useCurrentTimestamp = true
        }

}

build.gradleはこんな感じ。

$ ./gradlew jibDockerBuild

docker images でイメージを確認する

$ docker images
REPOSITORY                                                         TAG                 IMAGE ID            CREATED             SIZE
sample/jib-demo-app                                                latest              891911ccd0de        About a minute ago   133MB

イメージ作成できてました。簡単すぎる。

イメージを実行して確認する

$ docker run --rm -it -p 8080:8080 --name jib-demo-app sample/jib-demo-app  
Picked up JAVA_TOOL_OPTIONS: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.3.RELEASE)

2018-08-05 16:18:36.344  INFO 1 --- [           main] net.kosasaki.example.WebApplication      : Starting WebApplication on 115367cada6f with PID 1 (/app/classes started by root in /)

確認できたので、OKとする

実にカンタン。これからはコンテナの世界ですねー。

にしても、alpine-slimで133MBとかJavaはサイズが大きいなー。
Java11とかでサイズ小さくなるといいなー。

docker-credential-ecr-loginのインストール

docker-credential-ecr-login を使えば、楽だよってでてたので、インストール

(golang 入ってない人は yum | brew | apt-get でインストールする)

$ go get -u github.com/awslabs/amazon-ecr-credential-helper/ecr-login/cli/docker-credential-ecr-login

これでインストールおわり。

aws configureでaccess keyと secret access keyを設定する

$ aws configure --profile ecr 
AWS Access Key ID [**********************]: 
AWS Secret Access Key [**********************]: 
Default region name [ap-northeast-1]: 
Default output format [json]: 

ECRのログイン情報する

$ aws ecr get-login --no-include-email --region ap-northeast-1
docker login -u AWS -p ${long password}  https://${repository number}.dkr.ecr.ap-northeast-1.amazonaws.com

ログインコマンドが発行されるので、これを実行する

$ docker login -u AWS -p ${long password}  https://${repository number}.dkr.ecr.ap-northeast-1.amazonaws.com

WARNING! Using --password via the CLI is insecure. Use --password-stdin.
error getting credentials - err: exec: "docker-credential-ecr-login": executable file not found in $PATH, out: ``

変なエラーがでる。。。
とおもったら、 docker-credential-ecr-login にパスが通ってないもよう。

パスを通して再度実行して解決

$ vi ~/.bash_profile

export PATH=$PATH:~/go/bin  <- これを追加

Javaアプリをdocker化してくれるjibを環境ごとに分岐する

Java(Spring)アプリをdocker化してくれるんだけど、環境ごとに分けたいことはあるので、パラメータを切り替えられるようにする。

buildscript {
    ext {
        springBootVersion = '2.0.3.RELEASE'
                jibVersion = "0.9.8"
    }
    repositories {
        mavenCentral()
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath "gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:${jibVersion}"
    }
}

apply plugin: 'org.springframework.boot'
apply plugin: 'com.google.cloud.tools.jib'
    dependencies {
        compile('org.springframework.boot:spring-boot-starter-webflux')
        compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    }

/**
* jibの設定 ifで分岐する
*/
    if(project.build == 'product') {
        jib {
            from {
                image = 'adoptopenjdk/openjdk8:alpine'
            }
            to {
                image = 'sample/jib-demo-product-app'
            }
            container {
                jvmFlags = ['-Xms512m', '-Xdebug']
                mainClass = 'com.example.demo.DemoApplication'
                args = []
                ports = ['8080/tcp']
            }

        }
    } else {
        jib {
            from {
                image = 'adoptopenjdk/openjdk8:alpine'
            }
            to {
                image = 'sample/jib-demo-app'
            }
            container {
                jvmFlags = ['-Xms512m', '-Xdebug']
                mainClass = 'com.example.demo.DemoApplication'
                args = []
                ports = ['8080/tcp']
            }

        }
    }

上記のように設定し、gradleコマンドをキックするときに、引数を渡してあげればいい

$ ./gradlew -Pbuild=product

=================
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
sample/jib-demo-product-app   latest              4fe1925bb902        48 years ago        220MB

こんな感じで作成される。 48years ago ってでてるけど、なんなんだろ。まぁCREATEDだからいいか

他にもjibのタスク呼び出しとかあるが、JibExtensionとかいろいろ呼ぶの面倒そうなので、逃げでもある