メモ / Hashicorp Waypointを触る

# 概要

[Announcing HashiCorp Waypoint](https://www.hashicorp.com/blog/announcing-waypoint)

- あらゆるアプリケーションをビルド、デプロイ、リリースするための一貫した開発者ワークフロー
- いろんなプラットフォームをサポート

> Waypoint supports Kubernetes, HashiCorp Nomad, Amazon ECS, Google Cloud Run, Azure Container Instances, Docker, Buildpacks, and more.

- デプロイ後は、デプロイの検証やデバッグのためログ機能などを提供
- "developers just want to deploy."
    - アプリデプロイを完了するまでの学習コストが高くなっている
    - アプリのデプロイ場所によってツールセットが違う
- あらゆるアプリのデプロイを、1つのコマンド ( `waypoint up` ) で可能にする
- ビルド・デプロイ・リリースの3ステージ
    - デプロイとリリースは別
- デプロイしたアプリは、自動で生成されたURL（Let's encryptedを使用）で確認可能

# Waypoint Goals (公式docより)

1. Consistency of Workflows
2. Confidence in Deployment
3. Extensibility with the Ecosystem

ざっくり、アプリケーション開発者にインフラを意識させないツール、てとこ

- 使ってる言語やそのパッケージ方法、デプロイ先がどれであろうが、統一されたワークフローを実現
- Dockerfileやyamlを書かず、最低限のHCLファイルをセットするだけで済む世界

# Getting started

## CLIインストール・Waypointサーバの起動

手元のMacでwaypointコマンドを動かせるようにする

```bash
> brew tap hashicorp/tap
> brew install hashicorp/tap/waypoint
```

```bash
> waypoint --help
Welcome to Waypoint
Docs: https://waypointproject.io
Version: v0.1.4

Usage: waypoint [-version] [-help] [-autocomplete-(un)install] <command> [args]

Common commands
  build        Build a new versioned artifact from source
  deploy       Deploy a pushed artifact
  release      Release a deployment
  up           Perform the build, deploy, and release steps for the app

Other commands
  artifact        Artifact and build management
  config          Application configuration management
  context         Server access configurations
  deployment      Deployment creation and management
  destroy         Delete all the resources created for an app
  docs            Show documentation for components
  exec            Execute a command in the context of a running application instance
  hostname        Application URLs
  init            Initialize and validate a project
  install         Install the Waypoint server to Kubernetes, Nomad, or Docker
  logs            Show log output from the current application deployment
  runner          Runner management
  server          Server management
  token           Authenticate and invite collaborators
  ui              Open the web UI
  version         Prints the version of this Waypoint CLI
```

Waypointサーバをインストールしていく

- デプロイした後のログ確認とかは、このサーバ使ってやるっぽい
    - ※Waypointはクライアントとしてもサーバとしても動作するので、上記のCLI入れるだけでは完了しない

Dockerイメージpullしてきて、そのあとインストール

- `accept-tos` フラグは、waypoint.runを使ったURL公開サービスを使うための利用規約同意

```bash
> docker pull hashicorp/waypoint:latest

> waypoint install --platform=docker -accept-tos

✓ Installing Waypoint server to docker
✓ Server container started!
✓ Configuring server...
Waypoint server successfully installed and configured!

The CLI has been configured to connect to the server automatically. This
connection information is saved in the CLI context named "install-1604225581".
Use the "waypoint context" CLI to manage CLI contexts.

The server has been configured to advertise the following address for
entrypoint communications. This must be a reachable address for all your
deployments. If this is incorrect, manually set it using the CLI command
"waypoint server config-set".

Advertise Address: waypoint-server:9701
Web UI Address: https://localhost:9702
```

新しく作成されたサーバを指すコンテキストが認証付きで作成される。これで、クライアントがサーバのアドレスを知った状態で操作できる

動いてるコンテナ確認

- COMMANDの内容は、`/usr/bin/waypoint server run -accept-tos -vvv -db=/data/data.db -listen-grpc=0.0.0.0:9701 -listen-http=0.0.0.0:9702`

```bash
> docker container ls
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                              NAMES
xxxxxxxxxxxx        hashicorp/waypoint:latest   "/usr/bin/waypoint s…"   14 minutes ago      Up 14 minutes       0.0.0.0:9701-9702->9701-9702/tcp   waypoint-server
```

デプロイのワークフローとしては、

- Waypointクライアント（今回は自分のMac）がWaypointサーバ（今回はDocker for Macで動かしてるコンテナ）に接続 & ワークフロー開始
- クライアントが自身をランナーとして登録し、Waypointがビルドを実行できるようにする
- ビルドが終わると、Waypointサーバはコンテナイメージなど成果物をレジストリに送信
- 複数のクライアントが1つのサーバに接続し、デプロイやリリースを同時に行える

## アプリのデプロイ

Waypointで管理するアプリを用意する

- Hashicorpがサンプルアプリを公開してるので、まずはそれ使うことにする
    - [waypoint-examples/docker/ruby at main · hashicorp/waypoint-examples](https://github.com/hashicorp/waypoint-examples/tree/main/docker/ruby)

```bash
> ghq get https://github.com/hashicorp/waypoint-examples.git
```

いざビルド...の前に、Waypointの初期化が必要。

- `waypoint init`
    - （まだ無い場合は）`waypoint.hcl` が作成される
    - Hashicorpのサンプルアプリのレポジトリには、すでに`waypoint.hcl` が含まれる。例えばRubyプロジェクトのやつは以下

```
project = "example-ruby"

app "example-ruby" {
  labels = {
    "service" = "example-ruby",
    "env" = "dev"
  }

  build {
    use "pack" {}
  }

  deploy { 
    use "docker" {}
  }
}
```

- buildブロックの`use "pack"` は、Cloud Native Buildpackを利用してアプリをビルドするという設定
    - 自動で関連性の高いBuildpackを選んでくれるみたいだが...
        - 例えば、Railsアプリであれば、Ruby Cloud Native Buildpacks をつかう
- deployブロックの`use "docker"` は、アプリをDockerで実行する設定
- deploy先の選択は、以下を参照
    - [https://www.waypointproject.io/plugins](https://www.waypointproject.io/plugins)

WaypointがBuildpackを利用してDockerfileを作成するため、ユーザは自分でDockerfile書かなくてよい

- → Buildpackとは？？
    - [Heroku buildpack | Heroku](https://jp.heroku.com/elements/buildpacks)
    - [Buildpacks | Heroku Dev Center](https://devcenter.heroku.com/articles/buildpacks)
    - Googleもオープンソースのbuildpacksを出していた
        - [GoogleCloudPlatform/buildpacks: Builders and buildpacks designed to run on Google Cloud's container platforms](https://github.com/GoogleCloudPlatform/buildpacks)

ビルド完了後、アプリは成果物をローカル or リモートのレジストリに保存する

- 何も設定しないと、ローカルのDockerインスタンスに保存される
- [https://www.waypointproject.io/docs/lifecycle/build#registry](https://www.waypointproject.io/docs/lifecycle/build#registry)

Rubyのサンプルアプリをデプロイする。

- うまくいかない。いったん問題解決は後回しにする

> If you encounter an error when running up, it is sometimes effective to run context clear and the initialize the project again. Read about the sub-commands of context with the -h flag.

```bash
> waypoint up
» Building...
Creating new buildpack-based image using builder: heroku/buildpacks:18
✓ Creating pack client
❌ Building image
 │ 2020/11/02 10:23:33.748085 DEBUG:  Pulling image index.docker.io/heroku/buildpac
 │ ks:18
 │ 18: Pulling from heroku/buildpacks
 │ Digest: sha256:cc3bd9b65cc8654d18a625a2ebaba5106b4161868bf2fc0404b8c9b1adfe9a42
 │ Status: Image is up to date for heroku/buildpacks:18
 │ 2020/11/02 10:23:39.722176 DEBUG:  Selected run image heroku/pack:18
 │ 2020/11/02 10:23:44.021785 DEBUG:  Pulling image heroku/pack:18
 │ 18: Pulling from heroku/pack
 │ Digest: sha256:41cdc6d487fee6eba8d1f777061bb60553509c193e4bc164767fac8c5e59c564
 │ Status: Image is up to date for heroku/pack:18
 │ 2020/11/02 10:23:49.011934 DEBUG:  Creating builder with the following buildpack
 │ s:
 │ 2020/11/02 10:23:49.011949 DEBUG:  -> heroku/maven@0.1
 │ 2020/11/02 10:23:49.011952 DEBUG:  -> heroku/jvm@0.1
 │ 2020/11/02 10:23:49.011954 DEBUG:  -> heroku/java@0.1
 │ 2020/11/02 10:23:49.011957 DEBUG:  -> heroku/ruby@0.0.1
 │ 2020/11/02 10:23:49.011959 DEBUG:  -> heroku/procfile@0.5
 │ 2020/11/02 10:23:49.011960 DEBUG:  -> heroku/python@0.2
 │ 2020/11/02 10:23:49.011962 DEBUG:  -> heroku/gradle@0.2
 │ 2020/11/02 10:23:49.011964 DEBUG:  -> heroku/scala@0.2
 │ 2020/11/02 10:23:49.011966 DEBUG:  -> heroku/php@0.2
 │ 2020/11/02 10:23:49.011968 DEBUG:  -> heroku/go@0.2
 │ 2020/11/02 10:23:49.011970 DEBUG:  -> heroku/nodejs-engine@0.5.0
 │ 2020/11/02 10:23:49.011972 DEBUG:  -> heroku/nodejs-npm@0.3.0
 │ 2020/11/02 10:23:49.011974 DEBUG:  -> heroku/nodejs-yarn@0.0.1
 │ 2020/11/02 10:23:49.011977 DEBUG:  -> heroku/nodejs-typescript@0.0.2
 │ 2020/11/02 10:23:49.011981 DEBUG:  -> heroku/nodejs@0.1
 │ 2020/11/02 10:23:49.011984 DEBUG:  -> salesforce/nodejs-fn@2.0.1
 │ 2020/11/02 10:23:49.011988 DEBUG:  -> projectriff/streaming-http-adapter@0.1.3
 │ 2020/11/02 10:23:49.011992 DEBUG:  -> projectriff/node-function@0.6.1
 │ 2020/11/02 10:23:49.011994 DEBUG:  -> evergreen/fn@0.2
 │ 2020/11/02 10:23:54.636883 DEBUG:  Pulling image buildpacksio/lifecycle:0.9.1
 │ 0.9.1: Pulling from buildpacksio/lifecycle
 │ Digest: sha256:53bf0e18a734e0c4071aa39b950ed8841f82936e53fb2a0df56c6aa07f9c5023
 │ Status: Image is up to date for buildpacksio/lifecycle:0.9.1
 │ 2020/11/02 10:24:00.962552 DEBUG:  Using build cache volume pack-cache-0b6bcd685
 │ 02c.build
 │ 2020/11/02 10:24:00.962569 INFO:   ===> DETECTING
 │ [detector] heroku/ruby     0.0.1
 │ [detector] heroku/procfile 0.5
 │ 2020/11/02 10:24:01.444842 INFO:   ===> ANALYZING
 │ [analyzer] Previous image with name "index.docker.io/library/example-ruby:latest
 │ " not found
 │ 2020/11/02 10:24:01.847366 INFO:   ===> RESTORING
 │ 2020/11/02 10:24:02.241115 INFO:   ===> BUILDING
 │ [builder] -----> Installing bundler 1.17.3
 │ [builder] -----> Removing BUNDLED WITH version in the Gemfile.lock
 │ [builder] -----> Compiling Ruby/Rails
 │ [builder]        Command: 'set -o pipefail; curl -L --fail --retry 5 --retry-del
 │ ay 1 --connect-timeout 3 --max-time 30 https://s3-external-1.amazonaws.com/herok
 │ u-buildpack-ruby/heroku-18/ruby-2.6.6.tgz -s -o - | tar zxf - ' failed on attemp
 │ t 1 of 3.
 │ [builder]        Command: 'set -o pipefail; curl -L --fail --retry 5 --retry-del
 │ ay 1 --connect-timeout 3 --max-time 30 https://s3-external-1.amazonaws.com/herok
 │ u-buildpack-ruby/heroku-18/ruby-2.6.6.tgz -s -o - | tar zxf - ' failed on attemp
 │ t 2 of 3.
 │ [builder]
 │ [builder]  !
 │ [builder]  !     The Ruby version you are trying to install does not exist on th
 │ is stack.
 │ [builder]  !
 │ [builder]  !     You are trying to install ruby-2.6.6 on heroku-18.
 │ [builder]  !
 │ [builder]  !     Ruby ruby-2.6.6 is present on the following stacks:
 │ [builder]  !
 │ [builder]  !     - cedar-14
 │ [builder]  !     - heroku-16
 │ [builder]  !     - heroku-18
 │ [builder]  !
 │ [builder]  !     Heroku recommends you use the latest supported Ruby version lis
 │ ted here:
 │ [builder]  !     https://devcenter.heroku.com/articles/ruby-support#supported-ru
 │ ntimes
 │ [builder]  !
 │ [builder]  !     For more information on syntax for declaring a Ruby version see
 │ :
 │ [builder]  !     https://devcenter.heroku.com/articles/ruby-versions
 │ [builder]  !
 │ [builder] ERROR: failed to build: exit status 1
! failed with status code: 145
```

代わりに、next.jsのサンプルアプリのほうで試す

```bash
> cd docker/next-js
> waypoint init

> waypoint up

» Building...
Creating new buildpack-based image using builder: heroku/buildpacks:18
✓ Creating pack client
✓ Building image
 │ [exporter] Adding layer 'config'
 │ [exporter] Adding label 'io.buildpacks.lifecycle.metadata'
 │ [exporter] Adding label 'io.buildpacks.build.metadata'
 │ [exporter] Adding label 'io.buildpacks.project.metadata'
 │ [exporter] *** Images (aed9b7531e61):
 │ [exporter]       index.docker.io/library/example-nextjs:latest
 │ [exporter] Adding cache layer 'heroku/nodejs-engine:nodejs'
 │ [exporter] Adding cache layer 'heroku/nodejs-engine:toolbox'
 │ [exporter] Adding cache layer 'heroku/nodejs-engine:yarn'
 │ [exporter] Adding cache layer 'heroku/nodejs-yarn:node_modules'
✓ Injecting entrypoint binary to image

Generated new Docker image: example-nextjs:latest

» Deploying...
✓ Setting up waypoint network
✓ Starting container
✓ App deployed as container: example-nextjs-01EP3ATKDD8GVBS9JR3CBMPAC6

» Releasing...

The deploy was successful! A Waypoint deployment URL is shown below. This
can be used internally to check your deployment and is not meant for external
traffic. You can manage this hostname using "waypoint hostname."

           URL: https://duly-cute-vervet.waypoint.run
Deployment URL: https://duly-cute-vervet--v1.waypoint.run
```

Hashicorpのサービス上にプレビューURLが作成されている

- `https://duly-cute-vervet.waypoint.run`
- `https://duly-cute-vervet--v1.waypoint.run` のほうはバージョン番号が入ってる、バージョン管理できる？

ちなみに確認すると、nextjsアプリのコンテナが動いてることがわかる

- `/waypoint-entrypoint /cnb/lifecycle/launcher`

```
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                              NAMES
xxxxxxxxxxxx        example-nextjs:latest       "/waypoint-entrypoin…"   42 minutes ago      Up 42 minutes       0.0.0.0:32768->3000/tcp            example-nextjs-01EP3ATKDD8GVBS9JR3CBMPAC6
xxxxxxxxxxxx
        hashicorp/waypoint:latest   "/usr/bin/waypoint s…"   2 hours ago         Up 2 hours          0.0.0.0:9701-9702->9701-9702/tcp   waypoint-server
```

URLで見れる画面。

![Screen_Shot_2020-11-02_at_11.46.11_AM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1795/1d1665c2-db98-ef6b-18de-1306184ee82b.png)

画面を一部変更して再度デプロイしてみる

```bash
> waypoint up

» Building...
Creating new buildpack-based image using builder: heroku/buildpacks:18
✓ Creating pack client
✓ Building image
 │ [exporter] Reusing layer 'config'
 │ [exporter] Adding label 'io.buildpacks.lifecycle.metadata'
 │ [exporter] Adding label 'io.buildpacks.build.metadata'
 │ [exporter] Adding label 'io.buildpacks.project.metadata'
 │ [exporter] *** Images (e4122799b48d):
 │ [exporter]       index.docker.io/library/example-nextjs:latest
 │ [exporter] Reusing cache layer 'heroku/nodejs-engine:nodejs'
 │ [exporter] Reusing cache layer 'heroku/nodejs-engine:toolbox'
 │ [exporter] Reusing cache layer 'heroku/nodejs-engine:yarn'
 │ [exporter] Reusing cache layer 'heroku/nodejs-yarn:node_modules'
✓ Injecting entrypoint binary to image

Generated new Docker image: example-nextjs:latest

» Deploying...
✓ Setting up waypoint network
✓ Starting container
✓ App deployed as container: example-nextjs-01EP3E3B4KNMPAWT46EQS50468

» Releasing...

The deploy was successful! A Waypoint deployment URL is shown below. This
can be used internally to check your deployment and is not meant for external
traffic. You can manage this hostname using "waypoint hostname."

           URL: https://duly-cute-vervet.waypoint.run
Deployment URL: https://duly-cute-vervet--v2.waypoint.run
```

新しいコンテナが起動され、変更が反映される。

- デプロイ毎にプレビューURLが生成
- バージョン番号がついてないURLは、最新バージョンのURLへのエイリアスか

```bash
> docker container ls | grep nextjs
xxxxxxxxxxxx        example-nextjs:latest       "/waypoint-entrypoin…"   8 minutes ago       Up 8 minutes        0.0.0.0:32769->3000/tcp                example-nextjs-01EP3E3B4KNMPAWT46EQS50468
xxxxxxxxxxxx
        11b0ca7c1e3c                "/waypoint-entrypoin…"   About an hour ago   Up About an hour    0.0.0.0:32768->3000/tcp                example-nextjs-01EP3ATKDD8GVBS9JR3CBMPAC6
```

> For Docker deployments, both deploys will be active for the non-Deployment specific URL. As such, accessing that URL will return requests from both deployments.

どう言う意味だろう？

## デバッグ

デプロイ先のコンテナに入ってみる

```bash
> waypoint exec /bin/bash

heroku@xxxx:/$ ls
app  bin  boot	cnb  dev  etc  home  input  layers  lib  lib64	media  mnt  opt  proc  root  run  sbin	srv  sys  tmp  usr  var  waypoint-entrypoint  workspace

heroku@xxxx:/$ ls app
README.md  node_modules  package.json  pages  public  styles  waypoint.hcl  yarn.lock

heroku@xxxx:/$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
heroku       1  0.1  0.1 815404  3044 ?        Ssl  02:55   0:03 /waypoint-entrypoint /cnb/lifecycle/launcher
heroku      18  0.0  0.0 841040   704 ?        Sl   02:55   0:00 node /layers/heroku_nodejs-engine/yarn/bin/yarn.js start
heroku      43  0.0  0.0   4628     0 ?        S    02:55   0:00 /bin/sh -c next start
heroku      44  0.0  0.0 871980     0 ?        Sl   02:55   0:00 /layers/heroku_nodejs-engine/nodejs/bin/node /workspace/node_modules/.bin/next start
heroku      56  0.0  0.0  18508  1108 pts/0    Ss   03:13   0:00 /bin/bash
heroku      69  0.0  0.1  34404  2756 pts/0    R+   03:23   0:00 ps aux
```

デプロイのログ確認

```bash
> waypoint logs
2020-11-02T02:55:39.634Z 0F0X2G: yarn run v1.22.10
2020-11-02T02:55:39.660Z 0F0X2G: $ next start
2020-11-02T02:55:39.791Z 0F0X2G: ready - started server on http://localhost:3000
```

WebUIで、ビルド/デプロイ/リリースの情報がきれいに見れる

- 下記コマンドでブラウザが自動で開く
- ※今回は、WaypointサーバをローカルのDocker for Macで動かしてるので、ローカル用のコマンド

```bash
> waypoint ui -authenticate
```

接続先は、`https://localhost:9702/...`

- `waypoint server run` で起動したコンテナに接続してる

## デプロイ（リリース）の削除

```bash
> waypoint destroy

» Destroying releases...

» Destroying deployments...
Destroy successful!
```

アプリのDockerコンテナが消えてる。Web UIからも確認できる

- Waypointサーバは当たり前ながら消えないので、そっちは別途消す必要がある

# 参考

- [hashicorp/waypoint](https://github.com/hashicorp/waypoint)
- [Documentation | Waypoint by HashiCorp](https://www.waypointproject.io/docs)
- [Waypoint Tutorials - HashiCorp Learn](https://learn.hashicorp.com/waypoint)