3 年ぶりに cf push してみた

## はじめに

3 年ほど前に Cloud Foundry ネタで社外イベントに登壇したのですが、ひょんなことから社内勉強会でリバイバル発表することになりました。さすがに 3 年前とは成熟度の面で差があると思い、最新情報をキャッチアップするために Cloud Foundry 環境構築に踏み切りました。

AWS 上に Cloud Foundry をデプロイしましたので、以下の日本語ワークショップを参考に、3 年ぶりに ``cf push`` してみたいと思います。
https://github.com/Pivotal-Japan/cf-workshop/blob/master/deploy-application_python.md

### 前提条件

- Cloud Foundry CLI がインストール済みであること
- Cloud Foundry への接続情報が分かっていること

## ログインする

``cf login`` コマンドでログインします（API エンドポイントやユーザは、適宜読み替えてください）。

```zsh
cf login -a https://api.sys.pcf.hoge.com -u admin --skip-ssl-validation 
```

以下のような応答がありますので、途中でパスワードを入力します。

```
% cf login -a https://api.sys.pcf.hoge.com -u admin --skip-ssl-validation
API エンドポイント: https://api.sys.pcf.hoge.com

Warning: Your targeted API's version (3.80.0) is less than the minimum supported API version (3.85.0). Some commands may not function correctly.

パスワード: ＜パスワードを入力します＞

認証中です...
OK

Select an org:
1. aws-service-broker-org
2. system

組織 (enter to skip): 1
Targeted org aws-service-broker-org.

Targeted space aws-service-broker-space.

API エンドポイント:   https://api.sys.pcf.abeam.cc
API version:          3.80.0
ユーザー:             admin
組織:                 aws-service-broker-org
スペース:             aws-service-broker-space
```

## アプリケーションを準備する

アプリケーションディレクトリを準備します。

```zsh
mkdir hello-cf
cd hello-cf
```

適当なエディタで ``hello.py`` を作成します。"Hello World!" を返す単純なプログラムです。

```python:hello.py
from flask import Flask
import os

app = Flask(__name__)

port = int(os.getenv("PORT"))

@app.route('/')
def hello():
    return 'Hello World!'

if __name__ == '__main__':
    app.run(host = '0.0.0.0', port = port)
```

続けて ``requirements.txt`` を作成します。``hello.py`` 内で利用している軽量なウェブアプリケーションフレームワークである Flask をリストしておきます。

```:requirements.txt
Flask
```

続けて ``runtime.txt`` を作成します。今回は ``python-3.8.2`` を指定します。ビルドパックおよびランタイムバージョンの確認については、後述します。

```:runtime.txt
python-3.8.2
```

続けて ``Procfile`` を作成します。実行するコマンドを記述します（Heroku 互換です）。

```:Procfile
web: python hello.py
```

さいごに ``manifest.yml`` を作成します。のちほど ``cf push`` する際に参照されます。``hello`` アプリケーションの URL がランダムに採番されるように、``random-route: true`` を指定しています。また、ビルドパックの自動判別に時間が掛からないよう、``buildpack: python_buildpack`` で python であることを明示してます。

```yaml:manifest.yml
---
applications:
  - name: hello
    memory: 32m
    buildpack: python_buildpack
    random-route: true
```

作成したファイルを確認しておきます。

```
% ls -la
total 0
drwxrwxrwx 1 hoge hoge 4096 Aug 23 17:57 ./
drwxr-xr-x 1 hoge hoge 4096 Aug 23 18:19 ../
-rw-rw-rw- 1 hoge hoge   21 Aug 23 17:51 Procfile
-rw-rw-rw- 1 hoge hoge  215 Aug 23 17:48 hello.py
-rw-rw-rw- 1 hoge hoge  105 Aug 23 17:57 manifest.yml
-rw-rw-rw- 1 hoge hoge    6 Aug 23 17:48 requirements.txt
-rw-rw-rw- 1 hoge hoge   13 Aug 23 17:51 runtime.txt
```

以上でアプリケーションの準備は整いました。

## ビルドパックおよびランタイムバージョンを確認する

``cf buildpacks`` コマンドでビルドパックを確認しておきます。先ほどランタイムとして ``python-3.8.2`` を明示しました。順番が前後しますが、ランタイムバージョンを明示するためには、利用可能なバージョンを先に確認しておく必要があります。今回は、Python ランタイムを利用するので、``python_buildpack-cached-cflinuxfs3-v1.7.13.zip`` が対象で、バージョン 1.7.13 ということが分かります。

```
% cf buildpacks
admin としてビルドパックを取得しています...

position   name                     stack           enabled   locked   filename
1          staticfile_buildpack     cflinuxfs3      true      false    staticfile_buildpack-cached-cflinuxfs3-v1.5.6.zip
2          java_buildpack_offline   cflinuxfs3      true      false    java-buildpack-offline-cflinuxfs3-v4.29.1.zip
3          ruby_buildpack           cflinuxfs3      true      false    ruby_buildpack-cached-cflinuxfs3-v1.8.17.zip
4          nginx_buildpack          cflinuxfs3      true      false    nginx_buildpack-cached-cflinuxfs3-v1.1.8.zip
5          nodejs_buildpack         cflinuxfs3      true      false    nodejs_buildpack-cached-cflinuxfs3-v1.7.18.zip
6          go_buildpack             cflinuxfs3      true      false    go_buildpack-cached-cflinuxfs3-v1.9.12.zip
7          r_buildpack              cflinuxfs3      true      false    r_buildpack-cached-cflinuxfs3-v1.1.4.zip
8          python_buildpack         cflinuxfs3      true      false    python_buildpack-cached-cflinuxfs3-v1.7.13.zip
9          php_buildpack            cflinuxfs3      true      false    php_buildpack-cached-cflinuxfs3-v4.4.13.zip
10         dotnet_core_buildpack    cflinuxfs3      true      false    dotnet-core_buildpack-cached-cflinuxfs3-v2.3.9.zip
11         binary_buildpack         cflinuxfs3      true      false    binary_buildpack-cached-cflinuxfs3-v1.0.36.zip
12         binary_buildpack         windows2012R2   true      false    binary_buildpack-cached-windows2012R2-v1.0.36.zip
13         binary_buildpack         windows2016     true      false    binary_buildpack-cached-windows2016-v1.0.36.zip
14         binary_buildpack         windows         true      false    binary_buildpack-cached-windows-v1.0.36.zip
```

以下の URL にアクセスすると、Python ビルドパックのバージョン 1.7.3 に含まれているランタイムバージョン一覧を確認できます。Python 3.8 系は二つありますが新しい方を採用することにしました。
https://github.com/cloudfoundry/python-buildpack/releases/tag/v1.7.13

|name|version|cf_stacks|
|:--|:--|:--:|
|libffi|3.2.1|cflinuxfs3|
|libmemcache|1.0.18|cflinuxfs3|
|miniconda3|4.7.12.1|cflinuxfs3|
|pip-pop|0.1.4|cflinuxfs3|
|pipenv|2018.11.26|cflinuxfs3|
|python|3.5.7|cflinuxfs3|
|python|3.5.9|cflinuxfs3|
|python|3.6.9|cflinuxfs3|
|python|3.6.10|cflinuxfs3|
|python|3.7.6|cflinuxfs3|
|python|3.7.7|cflinuxfs3|
|python|3.8.1|cflinuxfs3|
|python|3.8.2|cflinuxfs3|
|setuptools|46.1.3|cflinuxfs3|

## プッシュする

いよいよ 3 年ぶりの ``cf push`` です。先に ``manifest.yml`` を用意しておいたので、オプションなしで実行します。

```
% cf push
admin としてアプリ hello を組織 aws-service-broker-org / スペース aws-service-broker-space にプッシュしています...
Applying manifest file /home/hoge/hello-cf/manifest.yml...
Manifest applied
Packaging files to upload...
ファイルをアップロードしています...
 767 B / 767 B [====================================================] 100.00% 1s

API がファイルの処理を完了するのを待機しています...

アプリをステージングし、ログをトレースしています...
   Downloading python_buildpack...
   Downloaded python_buildpack
   Cell 45944b4f-c5fe-4725-ba6e-f3c658bb4d68 creating container for instance 736549c1-ab02-47cc-a297-bfcc7cf64807
   Cell 45944b4f-c5fe-4725-ba6e-f3c658bb4d68 successfully created container for instance 736549c1-ab02-47cc-a297-bfcc7cf64807
   Downloading app package...
   Downloading build artifacts cache...
   Downloaded app package (767B)
   Downloaded build artifacts cache (683.1K)
   -----> Python Buildpack version 1.7.13
   -----> Supplying Python
   -----> Installing python 3.8.2
          Copy [/tmp/buildpacks/0b5ebc48cf1bada4c8df6d405fadd9b8/dependencies/866ea0523dd5d868281abacc21e1f976/python-3.8.2-linux-x64-cflinuxfs3-580151dd.tgz]
   -----> Installing pip-pop 0.1.4
          Copy [/tmp/buildpacks/0b5ebc48cf1bada4c8df6d405fadd9b8/dependencies/1cd0187e0e714e99bef932d4c22f6515/pip-pop-0.1.4-0a3b0f1b.tar.gz]
   -----> Running Pip Install
          Collecting Flask (from -r /tmp/app/requirements.txt (line 1))
            Using cached https://files.pythonhosted.org/packages/f2/28/2a03252dfb9ebf377f40fba6a7841b47083260bf8bd8e737b0c6952df83f/Flask-1.1.2-py2.py3-none-any.whl
          Collecting itsdangerous>=0.24 (from Flask->-r /tmp/app/requirements.txt (line 1))
            Using cached https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl
          Collecting Werkzeug>=0.15 (from Flask->-r /tmp/app/requirements.txt (line 1))
            Using cached https://files.pythonhosted.org/packages/cc/94/5f7079a0e00bd6863ef8f1da638721e9da21e5bacee597595b318f71d62e/Werkzeug-1.0.1-py2.py3-none-any.whl
          Collecting Jinja2>=2.10.1 (from Flask->-r /tmp/app/requirements.txt (line 1))
            Using cached https://files.pythonhosted.org/packages/30/9e/f663a2aa66a09d838042ae1a2c5659828bb9b41ea3a6efa20a20fd92b121/Jinja2-2.11.2-py2.py3-none-any.whl
          Collecting click>=5.1 (from Flask->-r /tmp/app/requirements.txt (line 1))
            Using cached https://files.pythonhosted.org/packages/d2/3d/fa76db83bf75c4f8d338c2fd15c8d33fdd7ad23a9b5e57eb6c5de26b430e/click-7.1.2-py2.py3-none-any.whl
          Collecting MarkupSafe>=0.23 (from Jinja2>=2.10.1->Flask->-r /tmp/app/requirements.txt (line 1))
            Using cached https://files.pythonhosted.org/packages/4b/20/f6d7648c81cb84815d0be935d5c74cd1cc0239e43eadb1a61062d34b6543/MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl
          Installing collected packages: itsdangerous, Werkzeug, MarkupSafe, Jinja2, click, Flask
            WARNING: The script flask is installed in '/tmp/contents621161296/deps/0/python/bin' which is not on PATH.
            Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
          Successfully installed Flask-1.1.2 Jinja2-2.11.2 MarkupSafe-1.1.1 Werkzeug-1.0.1 click-7.1.2 itsdangerous-1.1.0
          WARNING: You are using pip version 19.2.3, however version 20.2.2 is available.
          You should consider upgrading via the 'pip install --upgrade pip' command.
   Exit status 0
   Uploading droplet, build artifacts cache...
   Uploading droplet...
   Uploading build artifacts cache...
   Uploaded build artifacts cache (683.2K)
   Uploaded droplet (56.1M)
   Uploading complete

Waiting for app hello to start...

Instances starting...
Instances starting...
Instances starting...
Instances starting...

名前:                   hello
要求された状態:         started
経路:                   hello-wacky-bear-aj.apps.pcf.hoge.com
最終アップロード日時:   Sun 23 Aug 18:31:51 JST 2020
スタック:               cflinuxfs3
ビルドパック:           python

タイプ:           web
sidecars:
インスタンス:     1/1
メモリー使用量:   32M
開始コマンド:     python hello.py
     状態   開始日時               cpu    メモリー           ディスク           詳細
#0   実行   2020-08-23T09:32:06Z   0.0%   32M の中の 13.1M   1G の中の 202.9M
```

随分とあっけないですが、無事にプッシュされたようです。「あー、aws-service-broker-org 組織の aws-service-broker-space スペースにプッシュしちゃったなー」と若干後悔しながらも、手順を進めます。本来であれば、適切な組織およびスペースにプッシュすべきです。

## アプリを確認する

``cf app`` コマンドで ``hello`` アプリケーションの詳細情報を確認してみます。

```
% cf app hello
admin として組織 aws-service-broker-org / スペース aws-service-broker-space 内のアプリ hello の正常性と状況を表示しています...

名前:                   hello
要求された状態:         started
経路:                   hello-wacky-bear-aj.apps.pcf.hoge.com
最終アップロード日時:   Sun 23 Aug 18:31:51 JST 2020
スタック:               cflinuxfs3
ビルドパック:           python

タイプ:           web
sidecars:
インスタンス:     1/1
メモリー使用量:   32M
     状態   開始日時               cpu    メモリー           ディスク           詳細
#0   実行   2020-08-23T09:32:06Z   0.1%   32M の中の 13.2M   1G の中の 202.9M
```

## アプリにアクセスする

アプリケーション詳細情報の「経路」の値（http\://hello-wacky-bear-aj.apps.pcf.hoge.com/）がアプリケーション URL となります。アプリケーション名 ``hello`` のサフィックスである ``-wacky-bear-aj`` が自動採番された部分です。

実際にアクセスしてみると、期待通り "Hello World!" と表示されました。

## Apps Manager からも確認してみる

先ほどは ``cf app`` コマンドで確認したので、今度は Apps Manager から確認してみます。CLI と同様に ``hello`` アプリケーションが確認できます。Route 列の URL を選択すると、期待通り "Hello World!" と表示されました。こちらは https でのアクセスとなるため、証明書警告が表示されます。
![screenshot-apps.sys.pcf.abeam.cc-2020.08.23-18_49_49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319241/3036a411-3292-2c1d-3dc4-61fc5d150fe4.png)

## アプリを削除する

``cf delete`` でプッシュしたばかりの ``hello``アプリケーションを削除します。

```
% cf delete hello
アプリ hello を削除しますか? [yN]: y
admin として組織 aws-service-broker-org / スペース aws-service-broker-space 内のアプリ hello を削除しています...
OK

```

## ログアウトする

``cf logout`` でログアウトしておきます。

```
% cf logout
admin をログアウトしています...
OK

```

## さいごに

Cloud Foundry 環境準備に手間取りましたが、環境さえ準備できれば、あとはサクサクです。このサクサク感が Cloud Foundry 最大の魅力ですね。Kubernetes でのゴリゴリとは違った魅力があると思います。Cloud Foundry がマイクロサービスプラットフォームとして普及することを切に願っています。

### 参考リンク

https://github.com/Pivotal-Japan/cf-workshop/blob/master/deploy-application_python.md
https://qiita.com/syamamotorhead/items/0fd7d8740a07523af4fd
https://qiita.com/syamamotorhead/items/0e69836e579078a0a2ac
https://qiita.com/syamamotorhead/items/c9871a62ffe88071897c