年中アイス

いろいろつらつら

Apexでlambda slack POSTにGoを使う

以前のエントリで、Lambda Node.js 4.3を使ってSlackにPostしていました。

reiki4040.hatenablog.com

普段Javascriptは書かないので、Goで書いてApexでデプロイする版を試しました。

ApexはLambdaのコードを管理(?)、デプロイするツールで、PythonやNode.jsなどのLambda対応言語はもちろん、GoをLambdaで実行(Node.js経由)することができます。

Apex自体は参考にしたページの方が詳しいのでそちらを。

dev.classmethod.jp

qiita.com

Apexを使ってGoでslackにpostするLambda functionを作る

今回のApexプロジェクトディレクトリを作って、初期設定します。

mkdir post-slack
cd post-slack
apex init

Project nameとdescriptionを聞かれるので、project name: post-slackとdescriptionは空白のままEnter。

             _    ____  _______  __
            / \  |  _ \| ____\ \/ /
           / _ \ | |_) |  _|  \  /
          / ___ \|  __/| |___ /  \
         /_/   \_\_|   |_____/_/\_\



  Enter the name of your project. It should be machine-friendly, as this
  is used to prefix your functions in Lambda.

    Project name: post-slack

  Enter an optional description of your project.

    Project description:

  [+] creating IAM post-slack_lambda_function role
  [+] creating IAM post-slack_lambda_logs policy
  [+] attaching policy to lambda_function role.
  [+] creating ./project.json
  [+] creating ./functions

  Setup complete, deploy those functions!

    $ apex deploy

ディレクトリ、ファイルが作成され、Lambda function用のRoleが自動作成されます。

slackにPOSTするfunctionの作成

新しいfunction用のディレクトリを作ります。go-generalは、general channelにPOSTしていたののGo版という意味でつけてます。

mkdir functions/go-general

次に、ここにあるGoのファイルを持ってきます。

curl -o functions/go-general/main.go https://gist.githubusercontent.com/reiki4040/afe3bd4317992b4748b0983f51058fae/raw/078b143186e03b45322d8373d5747afa78e801b8/main.go

最後に、環境変数用のfunction.jsonを作成します。(自分の環境のslack URLに置き換えてください)

echo '{
  "environment":{
    "SLACK_WEBHOOK_URL": "REPLACE YOUR SLACK WEBHOOK URL"
  }
}' > functions/go-general/function.json

ディレクトリ/ファイル構成は、こんな感じになります。

post-slack/
├── functions/
│   ├── go-general/
│   │   ├── function.json
│   │   └── main.go
│   └── hello/
│       └── index.js
└── project.json

deploy (Lambda functionの作成)

apex deployだけだと、サンプルのhello functionもアップされるので、function名を指定します。

apex deploy go-general

以下のように作成されます。

 • creating function         env= function=go-general
 • created alias current     env= function=go-general version=1
 • function created          env= function=go-general name=post-slack_go-general version=1

あとは元のエントリにあるように、functionの詳細から[Test]で、同じようにJSONを与えてあげると、slackにPOSTされます。 同様に、中編後編をやると、API gatewayでWebAPIにできます。

所感

Apex便利ですね。Goだとサードパーティライブラリを使ってもバイナリにまとまるので、Lambdaの実行環境の影響を受けません*1 その代わり、このapexのディレクトリ構成上、Goのvendoringは一工夫要りそうな感じです。

参考など

*1:cgo関係はダメかもですが、pure goは性質上いけるはず

AWS CodeBuildでGoプロジェクトをビルドする

AWS TokyoリージョンにもCodeBuild等のCodeシリーズ(?)一式揃い、使ってみようということで、まずはCodeBuildを試してみました。

公式にGoのサンプルはあるんですが、他のライブラリ使ってないhello worldなので、CodeBuildの説明だけという感じでした。vendoringが試したいので、今回は昔コンセプト実装したrnbin*1のビルドをCodeBuildに任せる形で試してみました。

つまづきポイントとしては、glideでvendoringしても、cannot find packageになってしまうという点。回避策を書いてくれている方がいましたが、それでも解決せず、詳しく見たらそうかーという感じでした。

全体的なCodeBuild設定の流れ

  • ビルドソースを選ぶ(S3, CodeCommit, github) *2
  • ビルド方法を指定する(buildspec.ymlを書く or 直接ビルドコードをアップロード)
  • ビルド生成物の保存先を指定(S3のバケット+Path)
  • ビルド実行!

今回はgithubのpublic repository (rnbin)に、CodeBuild用のbuildspec.ymlを置いています。buildspec.ymlは、まだサンプルなので、featureブランチにpushして、master(default)のブランチにはマージしてない状態です。 このプルリク(色々試したので、コミットがめちゃくちゃ)が対象ブランチ。buildspec.ymlについては、後で説明します。

CodeBuildでBuild Projectを作成する

AWSコンソールから、CodeBuildを開いて、[Get Start] or [Create Project]とするとBuild Projectの作成画面になります。

f:id:reiki4040:20170625173506p:plain

Project nameは任意のものを。今回はsample-build-rnbinにしました。Descriptionは特にないので省略。

次にSourceを選択します。今回はSource Providerにgithubを使います。githubを選択すると、[Connect to Github]と出て、GithubへのアクセストークンをOAuthで求められます。認証し、public repositoryを選んで、https://github.com/reiki4040/rnbinを入れます。 次に、ビルドに使うイメージを選択します。

f:id:reiki4040:20170625173643p:plain

今回は、Codebuildに用意されているGolangの1.7.3を使いました。Use an image managed by AWS CodeBuildを選び、Operating systemはUbuntu(しかない)にします。Go最新のバージョンだと、docker hubなどから持ってきて使う必要がありますね。

build specificationはリポジトリのbuildspec.ymlを使うので、そのままUse the buildspec.yml in the source code root directoryを。

最後に、ビルド後のファイルを置くS3バケットとパスを指定します。

f:id:reiki4040:20170625174259p:plain

Amazon S3、artifacts nameは、S3のディレクトリになるので、今回はrnbinにします。Bucket nameは任意のS3バケットを選択します。

Service Roleはデフォルトで勝手に作ってくれるので、それに任せます。*3

[continue]を押すと、確認プレビューが出ます。Advancedの所は、ビルドマシンのスペックなど選択できますが、今回は省略したのでデフォルトのスペックで動くようになっています。

f:id:reiki4040:20170625175015p:plain

ビルドする

[Save and Build]を押すと、Build Projectが保存され、Buildが始まり、対象のハッシュを聞かれます。

f:id:reiki4040:20170625175507p:plain

省略するとデフォルトブランチの最新状態で実行されますが、今回はfeatureブランチの最新のコミットハッシュをコピーしてきて入れます。(画像のハッシュは途中のものなので、最後のものではないです)そして、[Start Build]を押すと開始されます。

f:id:reiki4040:20170625175557p:plain

あとは、ビルドのフェーズが着々と進み、In ProgressからSucceededやFailedなどやビルドのログが表示されます。ビルドのログは CloudWatch logsに記録されます。何か問題がある場合はそこを見て判断します。

最後まで成功すると、指定したS3のバケット/rnbin/にrnbinというバイナリが置かれています。*4

buildspec.yml概要と、vendoring回避策

リポジトリのbuildspec.ymlは以下。debug用のpwdecho $GOPATHも入ってます。

version: 0.1

phases:
  install:
    commands:
      - go get github.com/Masterminds/glide
  pre_build:
    commands:
      # debug
      - pwd
      - echo $GOPATH

      # install libraries
      - glide up

      # workaround for vendoring
      - mkdir -p /go/src/github.com/reiki4040/rnbin
      - mv * /go/src/github.com/reiki4040/rnbin/
      - mv .git /go/src/github.com/reiki4040/rnbin/
  build:
    commands:
      # workaround for vendoring
      - cd /go/src/github.com/reiki4040/rnbin && ./build.sh
  post_build:
    commands:
      # workaround for vendoring
      - cp /go/src/github.com/reiki4040/rnbin/rnbin .

artifacts:
  files:
    - rnbin

buildspec.yml概要

buildspec.ymlに書く内容は、主に4つのビルドフェーズと、ビルド生成物の出力定義(artifacts)です。 ビルドフェーズは以下4つです。

  • install
  • pre_build
  • build
  • post_build

必要なツールを入れる、依存解決など、ビルド自体、ビルド後の後始末など、といった感じで、それぞれ複数のコマンドを書けます。

rnbinには、build.shというスクリプトを使って、go buildの流れを実行できるようにしてあります。主にはgitからハッシュやversion、加えてgo versionなどを持ってきてgo buildするという処理が入っています。これをCodeBuildで実行させます。

今回は、glideをインストールして、ライブラリインストール、後述のvendoring回避策をやって、build.shを呼び出し、バイナリを移動させて、S3に保存する。となっています。

vendoringでハマる (回避はしているが、きれいでない)

glideでインストールしたライブラリですが、./vendor/ができているにもかかわらず、cannot find packageと言われてハマりました。使っている環境はgo1.7.3で、go1.5からvendoring ができますが、この機能は$GOPATH以下の場合のみ動作し、それ以外では動作しないとのこと。

試しにpwdecho $GOPATHで、パスを出してみると、GOPATHには含まれている。

コマンド 結果 ※Xの部分はビルドごとに数字変わります。
pwd /codebuild/output/srcXXXXXXXX/src
echo $GOPATH /go:/codebuild/output/srcXXXXXXXX/src

エラーを見ると、GOPATH以下のsrcを見ているようで、そもそもrnbin自体に含まれているs3backend packageを読み込めていない。

/usr/local/go/src/github.com/reiki4040/rnbin/s3backend (from $GOROOT)
/go/src/github.com/reiki4040/rnbin/s3backend (from $GOPATH)
/codebuild/output/srcXXXXXXXX/src/src/github.com/reiki4040/rnbin/s3backend

つまり、currentのパッケージも読めないと。vendorが読めないのは、GOPATH以下ですが、$GOPATH/src/github.com/reiki4040/rnbinという形になっていないのが原因っぽい。そういうことか。

参考にしたページでは、$GOPATH以下に全部コピーして、ビルドする回避策が提示されていましたが、これだと完全には解決しませんでした。

前述の通り、$GOPATHには:区切りで2つ入っているので、そのまま使うとうまく動作していない様子。それなら、/goはまぁ入ってるでしょうと割り切り、$GOPATHを使わず、直接/go/src/github.com/reiki4040/rnbinといったようにコピーして実行していったらやっと通りました。

vendoring回避後のartifactsのファイル指定

生成したものをS3に保存するため、buildspec.ymlのartifactsの所にファイル名を書くんですが、goプロジェクト一式を/go以下にコピーして、ビルドした関係上、そっちに生成されています。

ただ、以下のように指定すると、S3にもそのディレクトリ構造がそのまま残ってしまいました。

artifacts:
  files:
    - /go/src/github.com/reiki4040/rnbin/rnbin

これはpost_buildのcommandにcp /go/src/github.com/reiki4040/rnbin/rnbin .とcurrentにバイナリをコピーしてくるコマンドを追加しました。commandは1行ずつ独立して実行されるので、.で持って来れます。

これでartifactsの所にはrnbin (生成バイナリのファイル名)のみを指定して、S3にもそのバイナリファイルだけが保存されます。

別ブランチの指定

サンプルだったのでfeatureブランチを使いました。最初はpre_buildにgit checkoutを入れていましたが、start buildでfeatureブランチのハッシュを指定したらfeatureブランチ(というかハッシュのやつ)で落とされたので、不要でした。

まとめ

EC2立てずに、マネージドなサーバでビルドできるところがいいですね。githubじゃなくても、S3にファイルあげてもいいし、CodeCommitにしてもいいので、AWS使ってる人は手をつけやすいかも。vendoringハマりましたが、Jenkins用のインスタンス作って運用するのは手間なので、その点はマネージドの強み。前後の作業も、AWSマネージドでやれるなら便利そうですね。他のCIサービスと比べてどうかは、他やってないのでまだわからず。

glideなどでのvendoringやサブパッケージは、普通に使うと思うので、CodeBuild側でやらなくていいようにしてくれると嬉しいですね。

参考

*1:複数のS3バケットを束ねて、リクエスト制限を分散できるようにするコンセプトのやつ

*2:githubは、OAuth通すので、プライベートリポジトリも行けそうな雰囲気(試してはいないです)

*3:ビルド中にAWSリソースにアクセスする場合などは、必要な権限を持つRoleを作っておいてそれを選択します。

*4:rnbinのbuild.shは未指定だとMac用のバイナリを作っています

DeploymentとServiceをyamlファイルで定義する

kubectlコマンドとオプションでnginxをminikube上で動かしました。 今回は、コマンドで起動内容を指定するのではなく、定義ファイルを使って動かすようにします。定義ファイルにすることでgitで管理できるようになります。

コマンドの振り返り

以下のように起動して、接続できるようにしまていました。

# nginxの起動
kubectl run nginx --image=nginx:1.11 --port=80

# Macから接続できるように
kubectl expose deploy nginx --name=nginx-nodeport --port=80 --target-port=80 --type="NodePort"

これは実際に何をやっているかというと、Deploymentという機能を使ってnginxコンテナを起動し、Serviceを使ってnginxコンテナにアクセスできるようにしています。

Deployment

Deploymentは、複数のコンテナを並列起動し、世代管理できる仕組みです。今回Deployment(+ReplicaSet, Pod)自体が何かというのはあまり重要ではないので省略。以下の記事で細かく解説されています。

qiita.com

Service

Serviceは複数のコンテナへのアクセスを仲介してくれるロードバランサーです。個々のコンテナのアクセス方法を把握しなくても、Serviceの受付口だけ知っていれば、通信できます。

定義ファイル(yaml)にする

定義ファイルはJSONyaml形式が使えます。他のプログラムを仲介する場合はJSONが良さそうですが、設定管理なら個人的にはyamlが好きです。(コメントアウトやコメント書ける点が良い)

nginx-deploy.yml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 2
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.11
        ports:
        - containerPort: 80

kubectl runで指定していたもの+を定義します。

プロパティ 説明
apiVersion Deploymentはベータ開発中なので、extentions/v1betaだそうです *1
kind kubectl runで動かしていたので、隠れていましたが、実態はDeploymentなので明示します。
metadata.name kubectl runの後に指定していた名前
spec.replicas --replicasオプションで指定できる、レプリカ数(コンテナの並列数)
spec.template.
metadata.labels
識別するための任意のKeyValue
spec.template.spec.
containers.name
コンテナの名前
spec.template.spec.
containers.image
--imageオプションで指定していたコンテナイメージ
spec.template.spec.
containers.ports.
containerPort
--portオプションで指定したコンテナの公開しているポート

続いてSerivce。kubectl exposeで指定したもの+を定義します

service.yml

apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport
spec:
  type: NodePort
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: nginx
プロパティ 説明
apiVersion ServiceはDeploymentと異なりv1です。
kind 同様にkubectl exposeを使っていましたがServiceを明示します。
metadata.name --nameオプションで指定していたもの
spec.type --typeオプションで指定していたもの
spec.ports.port --portで指定したいたもの
spec.ports.protocol TCPを明示
spec.ports.targetPort --target-portで指定していたコンテナに対するポート
spec.selector 前述のDeploymentのlabelと関係します。後で詳しく。

起動

kubectl createコマンドで作成(起動)します。

kubectl create -f nginx-deployment.yml
kubectl create -f service.yml

-fは同時に複数指定も可能です。

kubectl create -f nginx-deployment.yml -f service.yml

minikube経由でブラウザ起動して確認。nginxのwelcomeページが見れます。

minikube service nginx-nodeport

DeploymentのlabelとServiceのselector

kubectl exposeコマンドは、その後にdeploy nginxと指定していました。これはnginxという名前 のdeploymentをターゲットにするという意味です。定義ファイルの場合は、labelとselectorで紐付けが行われています。

Serviceのselectorで指定したkey:valueと一致するDeployment*2に、リクエストを流すようになります。 run: nginxを指定していますが、特にrunというkeyにしなくても、Deploymentのlabelをapp: httpserverにして、Serviceのselectorも同様に指定することでもリクエストが流れます。一致すればOKです。

Deployment以外にもlabelやselectorを書けるので、nameよりも柔軟に対象を決めることができるようです。

Labels and Selectors | Kubernetes

いろいろなところで、deploy nginxなど、いちいち名前を書いてられないので、labelをつけて、複数のターゲットを同一label名で識別できるようにすることを目的としているようです。でもlabelは多分もうちょっと詳しく調べないとよくわからず。

参考

*1:http://stackoverflow.com/questions/38547229/apiversion-and-beta-versions

*2:DeploymentじゃなくReplicaSetかもしれない?

Linuxでメモリ使用量が増え続けた

AmazonLinux 2017.03にnginx乗せて稼働させてたら、なぜかメモリ使用量が、1日ちょっとで2GB後半にさしかかりました。cacheではなくusedを徐々に消費してたので、これは何かリークしてる疑い。

プロセス等を見てもメモリを使っているものもいないし、疑いのあるプロセスをrestartしても改善しませんでした。

何だろうなーと調べてみたらすぐ出てきました。特にAmazonLinuxは関係なし。

dev.classmethod.jp

上記ページと同じく、NSSの問題で、curlがdentryというディレクトリ階層構造の管理をしているキャッシュを多く消費してしまうと。curlhttpsの監視が動いており、それが5分に1回なので、徐々にリークした様子。1時間に100MB程度ずつ増加していたようです。

回避策は、NSS_SDB_USE_CACHE=YESという環境変数を指定すること。とりあえず監視スクリプトexport NSS_SDB_USE_CACHE=YESを追加したら、増加が止まりました。

溜まったキャッシュは、以下のようにして解放されました。

echo 2 > /proc/sys/vm/drop_caches

>>でも>でもどっち動きますが多分>の方が適切?2という値は対象のキャッシュによって異なります。

クリアする対象キャッシュ
1 ページキャッシュ
2 dentry,inode
3 ページキャッシュ,dentry,inode

まとめ

じわじわ増えてく系のメモリリークは怖いです。調べたらたくさん出てきたので、割とメジャーな要因みたいですね。

Slabは知らなかったので調べてみたら、ざっくり言うとカーネル側のキャッシュとのこと。細かいメモリ周りはやっぱよくわかってない感。

参考

minikubeで自分の作ったimageを使う

前回minikubeの実行環境を作りました。公開されているnginxのimageを使いましたが、実際は自分でimageを作成し、それを実行させることがほとんどだと思います。minikubeはdockerを内包しているので、そこでdocker buildすればimageが登録され、使うことができます。

nginxに静的ページを追加したコンテナを作って試す

まず、minikubeのdockerを使うために以下を実行します。

eval $(minikube docker-env)

次にお試し用のpage.htmlとDockerfileを作ります。

# page.html
echo '<html>
  <head><title>this is page</title></head>
  <body>original page</body>
</html>' > page.html

# Dockerfile 
echo 'FROM nginx:1.11

COPY page.html /usr/share/nginx/html/page.html' > Dockerfile

ファイル構成としてはこんな形になります。

k8s/  ・・・名前はなんでもよくここにいる状態でeval $(minikube docker-env)
  |- Dockerfile
  +- page.html

imageを作ります。タグはlatestだと動かないので、適当にバージョンつけます。

docker build -t example/nginxpage:0.1.0 .

k8sで動かします。

# コンテナ起動
kubectl run nginxpage --image=example/nginxpage:0.1.0 --port=80

# Macからアクセスできるように
kubectl expose deploy nginxpage --name=nginxpage-nodeport --type="NodePort"

ブラウザで確認します。

minikube service nginxpage-nodeport

標準ブラウザが立ち上がり、nginxのwelcomeページが表示されるので、URL欄に/page.htmlを追加します。 そうすると、original pageと表示され、自分で作ったコンテナが利用できていることがわかります。

参考

ローカルでkubernetesを動かせるminikubeを試す

kubernetes(以降k8s)は、GKE(GoogleContainerEngine)を使うのが簡単らしいですが、とりあえずローカル実行できる環境が欲しくなったりします。

minikubeは、VirtualBoxなどの上にk8sの環境を構築してくれるツールです。今回はとりあえずMac上にk8s環境を作り、nginxを動かしてアクセスするところまでやってみます。

インストール

以下の2つのツールと関連するものをインストールします。

  • kubectl: k8sの操作を行うコマンド
  • minikube: ローカルにk8s環境を作るコマンド

kubectlのインストール

gcloudコマンドでインストール管理できるので、gcloudコマンドを入れます。

ダウンロードページから、MacOS用の、tar.gzをダウンロードし解凍し、install.shを実行します。

tar xzvf google-cloud-sdk-145.0.0-darwin-x86_64.tar.gz
google-cloud-sdk/install.sh

注意点として、Python2.7が必要です。Mac標準なら大丈夫で、何か入れてたら、頑張って2.7にしましょう。pyenv(今env系は何がデファクトなんだろうか)とか入れればできるのかな。

kubectlは、gcloud componentsコマンドでインストールできます。

gcloud components install kubectl

他にもGCP関連のツール群はこのgcloud componentsで入れられます。

minikubeのインストール

今回はVirtualBox上に作るので、先にダウンロードページからdmgを落としてきてインストールします。

次にminikubeです。リリースページにあるコマンドでインストールします。最後にsudo で移動させてるので管理者パスワードを聞かれます。*1

curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.18.0/minikube-darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/

k8s環境の構築

構築と書いてますが、以下コマンドで済みます。(が少し時間かかります)

minikube start

k8sのイメージを落としてきて、起動し、kubectlに登録してくれます。終わったら、kubectlで接続先のk8s環境を確認します。

kubectl config get-contexts

CURRENT   NAME       CLUSTER    AUTHINFO   NAMESPACE
*         minikube   minikube   minikube

他の環境がないととりあえずminikubeだけです。GKEとか使うとここが増えます。

nginxを動かしてアクセスする

以下コマンドでnginxコンテナを動かします。

kubectl run nginx --image=nginx:1.11 --port=80

--imageオプションでdockerのimage名とtagを指定します。--portでコンテナが公開しているポートを指定します。

k8s上でコンテナは動き出しますが、これだけだとまだMacからアクセスはできません。以下でにアクセスできるようにします。

kubectl expose deployment nginx --name=nginx-nodeport --port=80 --target-port=80 --type="NodePort"

kubectl expose deploymentの後のnginxは、kubectl runの後に指定した名前(今回はnginx)と同じです。

これでMacからアクセスできるようになるんですが、どのIPとポートなのかわかりません。これはminikubeが直接ブラウザで開いてくれるので、それを使います。

minikube service nginx-nodeport

minikube serviceの後に指定してあるnginx-nodeportは、手前のkubectl exposeで指定した--nameの値です。

これで標準ブラウザが立ち上がり、VirtualBox仮想マシンIPと自動で割り当てられたポートでページが開かれます。今回だとnginxのwelcomeページが表示されます。

URLだけ欲しい場合は--urlオプションをつけます。

minikube service nginx-nodeport --url

# portは自動的に割り当てられます
http://192.168.99.100:31430

なぜMacからk8sのコンテナにアクセスできるのか

とりあえずやるところだけ先に書きましたが、ネットワーク周りをもう少し。今回幾つか手順を踏んで、Macからk8sのコンテナにアクセスできるようになっています。この先の説明に出てくるIPやポートは、今回私が試したものなので、環境によって異なる場合があります。

まず、MacVirtualBox仮想マシン間は、専用のネットワークが構成されて、つながっています。これは192.168.99.0/24です。

k8sは自身のネットワークを構成します。10.0.0.0(サブネットマスクパッとわからず)で、k8sネットワークが作られています。このネットワークは、Macからは直接アクセスできません。

そこで、kubectl expose--type="NodePort"を使って、k8sネットワーク上のアクセス先と、ノード(VirtualBox仮想マシン)をつなげています。今回だとMac<->VirtualBoxネットワークとk8sネットワークをつなげるために、kubectl exposeしているという方が正確です。本来は冗長化した複数のコンテナのアクセス先をまとめるためにkubectl exposeを使います。

--type=“NodePort”によって、VirtualBox仮想マシン192.168.99.100:31430(ポートは自動的に割り当てられる)が、k8sネットワーク上の10.0.0.161:80(IPは自動的に割り当てられる)にフォワードされるようになっています。k8sの方はkubectl get serviceで確認できます。VirtualBoxの方は、前述のminikube service nginx-portnode --urlです。

kubectl get service

NAME             CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
kubernetes       10.0.0.1     <none>        443/TCP        2d
nginx-nodeport   10.0.0.161   <nodes>       80:31430/TCP   27m

アクセスの流れは以下になります。

Mac(VirtualBox network) 192.168.99.1
↓
minikube仮想マシン(VirtualBox network) 192.168.99.100:31430
↓
nginx-nodeport (k8s network)10.0.0.161:80
↓
nginx container(k8s networkのどこかIPとポート)

後始末

起動したものを止める方法

kubectl get service
kubectl delete service nginx-nodeport
kubectl get service

kubectl get deployment
kubectl delete deployment nginx
kubectl get deployment

minikube stop

まとめ

とりあえずローカルで動かすことができました。*2 公開、運用することなどを考えると、GKEが良さそうではありますが、まずは試すという点ではminikubeでもいいのかなと思います。

参考など

*1:特に最後の/usr/local/bin/移動は必須ではないので、その部分を除いて、./minikubeや、別のディレクトリに置いてPATHを通しても良いです。

*2:と言ってもコンテナイメージはdockerから持ってくるので完全にローカルというわけでもないですが

リリースを自動化したら思ったより楽になった

rnzooの0.5.0を開発していくにあたって、機能的な追加の他に、リリースの自動化を行いました。もともとビルド自体はbashスクリプトで自動化していて、dockerを使ったコンテナ上でのビルドとアーカイブファイルの作成を行っていました。

今回、devバージョンをちょこちょこ出しながら進めるために、リリースにかかる手間を減らしたくなったので、少し腰を据えて改善しました。おかげで0.5.0-devは6まで簡単に繰り返しリリースしていくことができました。

以前

実際のリリース(homebrewに反映させる)は、毎回以下をやっていました。

書くとあんまりたいしたことないですが、手作業満載で、頻繁にやらない分、あれどうしてたっけみたいな状態になっていました。

何をやったか

単純にスクリプト化しました。とりあえず動作確認できたら、tag作ってリリーススクリプト実行してリリースされるというところまで。詳細は以下プルリクを参照ください。 https://github.com/reiki4040/rnzoo/pull/20/files

hubコマンドを使って、リリースファイルをアップロード

調べてみたらhubコマンドでできるということで、インストールしてスクリプトに追加しました。

Pull Requestを自動で作成する

こっちに書いたように、関連するプルリクを自動で作成して、最後確認してマージするように。別にPullRequestにせず、masterにそのままpushでもいいんですが、応用が利きそうなので、あえてPullRequestを経由する形にしました。

未解決

テスト

今回homebrewのauditだけ入れていますが、この自動化に際して、hashが間違っていたり、対象ファイルが存在しない(url間違っていた)などを拾ってくれたので、テスト大事ですね。

CI/CDサービスとの連携

まだ自分でキックしないといけないので、自動で開始できるともっと楽になるはず。プルリク作ったら自動テスト実施とか、マージしたらリリースみたいな自然なフローをサポートしてくれる形にしたい。

まとめ

当たり前ですが、自動化すると手間とミスが減るので楽ですね。プロジェクトの最初で足回りちゃんと作るのが後で効いてくるんだなと実感しました。地味地味としたところの突っ掛かりがなくなると、集中しやすくなります。