--- title: cf-for-k8s(CF4K8s) 0.1.0をKind上にインストールする tags: ["Cloud Foundry", "Kubernetes", "CF4K8s"] categories: ["Dev", "PaaS", "CloudFoundry", "CF4K8s"] date: 2020-04-16T17:40:39Z updated: 2020-04-17T09:14:46Z --- Cloud FoundryをKubernetes上にインストールする[cf-for-k8s (CF4K8s)](https://github.com/cloudfoundry/cf-for-k8s)の0.1.0がリリースされたので試してみます。 今回は[Kind](https://github.com/kubernetes-sigs/kind)をLaptopにインストールし、その上にCloud Foundryをインストールします。 > CFをk8s上にデプロイするプロジェクトとしては[KubeCF](https://github.com/cloudfoundry-incubator/kubecf)もありますが、
> KubeCFは既存のCFのコンポーネントをBOSHの概念と共にKubenetesに移植したプロジェクトです。既存のCF利用者からすると、短期的にはKubeCFの方が移行しやすいかもしれません。
> 一方、cf-for-k8sは、CFのコンポーネントをKubernetesの世界に合わせて置き換えたり(Envoy, Istio, Fluentd, Kpackなど)、書き換えたりしています。
> 既存CF利用者視点での互換性はKubeCFに比べて低いですが、将来的に見るとcf-for-k8sのアプローチの方が理にかなっているように思えます。なお、KubeCFはHelmでインストールし、cf-for-k8sは[kapp](https://get-kapp.io/)でインストールします。
> cf-for-k8sは[VMware Tanzu Application Service for Kubernetes (TAS for k8s)](https://network.pivotal.io/products/tas-for-kubernetes)のベースとなっています。 ちなみに、ざっくりと、これまでのCloud Foundry (for BOSH)とCloud Foundry for k8sのコンポーネントの違いは次の表のようになります。
| 機能 | Cloud Foundry for BOSH | Cloud Foundry for k8s | ----|----|----| | Routing、Load Balancing | Go Router | **Istio/Envoy** | | API | Cloud Controller | Cloud Controller | | コンテナ管理 | Diego | **Kubernetes** | | コンテナイメージビルド | Cloud Foundry Buildpack | **Cloud Native Buildpack** | | Identity管理 | UAA | UAA | | ロギング | Loggregator | **Fluentd** (Log Cacheは残る) | | インフラライフサイクル管理 | BOSH | **Kubernetes** |
本記事の内容は基本的に次のドキュメントの通りです。 https://github.com/cloudfoundry/cf-for-k8s/blob/master/docs/deploy-local.md **目次** ### CLIのインストール * [`kubectl`](https://github.com/kubernetes/kubectl) * [`kind`](https://github.com/kubernetes-sigs/kind) * [`kapp`](https://get-kapp.io/) (cf-for-k8sのデプロイに使用します) * [`ytt`](https://get-ytt.io/) (yamlのpatchを適用するために使用します) * [`bosh`](https://github.com/cloudfoundry/bosh-cli) (yaml内のパスワードとTLS証明書を自動生成するために使用します) * [`cf`](https://github.com/cloudfoundry/cli) をインストールします。 ``` brew install kubectl brew install kind brew install k14s/tap/kapp brew install k14s/tap/ytt brew install cloudfoundry/tap/bosh-cli brew install cloudfoundry/tap/cf-cli ``` 動作確認したバージョンは ``` $ kind --version kind version 0.7.0 $ kubectl version --client=true Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.3", GitCommit:"06ad960bfd03b39c8310aaf92d1e7c12ce618213", GitTreeState:"clean", BuildDate:"2020-02-13T18:08:14Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"darwin/amd64"} $ kapp version kapp version 0.24. $ ytt version ytt version 0.27.1 $ bosh -v version 6.2.1-a28042ac-2020-02-10T18:41:00Z $ cf -v cf version 6.51.0+2acd15650.2020-04-07 ``` です。 ### cf-for-k8sマニフェストの取得 [`0.1.0`](https://github.com/cloudfoundry/cf-for-k8s/releases/tag/v0.1.0)を使用します。 ``` git clone https://github.com/cloudfoundry/cf-for-k8s.git -b v0.1.0 ``` ### Kubernetesクラスターの作成 cf-for-k8sで使用するKubernetesをKindで作成します。Kind用のconfigは[`cf-for-k8s/deploy/kind/cluster.yml`](https://github.com/cloudfoundry/cf-for-k8s/blob/v0.1.0/deploy/kind/cluster.yml)に用意されています。 ``` kind create cluster --config=./cf-for-k8s/deploy/kind/cluster.yml ``` Kindでは`LoadBalancer` typeの`Service`を作成できないため、hostの`443`ポートをKind内の`31443`ポートに、hostの`80`ポートを`31080`ポートにマッピングするように設定し、 cf-for-k8sが`LoadBalancer`の代わりに`NodePort`を使用しても、ホストから`443` or `80`ポートでアクセスできるようにしています。 クラスタが作成されたら`kubectl`で動作確認します。 ``` $ kubectl cluster-info Kubernetes master is running at https://127.0.0.1:32769 KubeDNS is running at https://127.0.0.1:32769/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy $ kubectl get node NAME STATUS ROLES AGE VERSION kind-control-plane Ready master 10m v1.17.0 $ kubectl get pod -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-6955765f44-n4qzd 1/1 Running 0 3m42s kube-system coredns-6955765f44-thqj8 1/1 Running 0 3m42s kube-system etcd-kind-control-plane 1/1 Running 0 3m57s kube-system kindnet-s9l7m 1/1 Running 0 3m42s kube-system kube-apiserver-kind-control-plane 1/1 Running 0 3m57s kube-system kube-controller-manager-kind-control-plane 1/1 Running 0 3m57s kube-system kube-proxy-jfbm8 1/1 Running 0 3m42s kube-system kube-scheduler-kind-control-plane 1/1 Running 0 3m57s local-path-storage local-path-provisioner-7745554f7f-vnwh9 1/1 Running 0 3m42s ``` KindにはMetrics Serverが含まれておらず、これがないと[`cf push`でエラーが発生する](https://github.com/cloudfoundry/cf-for-k8s/issues/123)ので、Metrics Serverを別途インストールしておきます。 ``` kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.6/components.yaml ``` ### Cloud Foundryのインストール いよいよk8s上にCloud Foundryをインストールを行います。 まずは、ソースコードを`cf push`した際にCloud Native Buildpackで作成されるDockerイメージをデプロイするDockerレジストリのアカウント情報を設定します。 ここではDockerHubを使用します。 また、パスワードや証明書を自動生成して[`./cf-for-k8s/hack/generate-values.sh`](https://github.com/cloudfoundry/cf-for-k8s/blob/v0.1.0/hack/generate-values.sh)を実行して設定値を作成します。 CFのドメインには`local.maki.lol`を使用します。 > `*.local.maki.lol`及び`*.apps.local.maki.lol`、`*.sys.local.maki.lol`はAレコードで`127.0.0.1`を返すように登録s亭あります。誰でも利用可能です。 ``` export DOCKERHUB_USERNAME=....... export DOCKERHUB_PASSWORD=.... ./cf-for-k8s/hack/generate-values.sh -d local.maki.lol > /tmp/cf-values.yml cat <> /tmp/cf-values.yml app_registry: hostname: https://index.docker.io/v1/ repository: ${DOCKERHUB_USERNAME} username: ${DOCKERHUB_USERNAME} password: ${DOCKERHUB_PASSWORD} EOF ``` 設定ファイルは`/tmp/cf-value.yml`に出力されます。`kapp`及び`ytt`を使用して次のコマンドでデプロイします。 ``` kapp deploy -a cf \ -f <(ytt -f ./cf-for-k8s/config \ -f /tmp/cf-values.yml \ -f ./cf-for-k8s/config-optional/remove-resource-requirements.yml \ -f ./cf-for-k8s/config-optional/use-nodeport-for-ingress.yml) ``` ベースのマニフェストファイルは`cf-for-k8s/config`に含まれます。これに対して、次の差分ファイルを`ytt`で適用しています。 * [`cf-for-k8s/config-optional/remove-resource-requirements.yml`](https://github.com/cloudfoundry/cf-for-k8s/blob/v0.1.0/config-optional/remove-resource-requirements.yml) ... Kindでもデプロイできるようにリソース(CPU、メモリ)の下限の制約を除外する * [`cf-for-k8s/config-optional/use-nodeport-for-ingress.yml`](https://github.com/cloudfoundry/cf-for-k8s/blob/v0.1.0/config-optional/use-nodeport-for-ingress.yml) ... IstionのIngress Gatewayに`NodePort`を使用する `y`を入力してインストールを開始します。次のようなログが流れてインストールが成功します。 ``` 9:02:17PM: ---- applying 36 changes [0/245 done] ---- 9:02:17PM: create customresourcedefinition/builds.build.pivotal.io (apiextensions.k8s.io/v1beta1) cluster 9:02:17PM: create customresourcedefinition/builders.build.pivotal.io (apiextensions.k8s.io/v1beta1) cluster 9:02:17PM: create customresourcedefinition/clusterbuilders.build.pivotal.io (apiextensions.k8s.io/v1beta1) cluster 9:02:17PM: create customresourcedefinition/custombuilders.experimental.kpack.pivotal.io (apiextensions.k8s.io/v1beta1) cluster 9:02:17PM: create customresourcedefinition/customclusterbuilders.experimental.kpack.pivotal.io (apiextensions.k8s.io/v1beta1) cluster ...(略)... 9:07:43PM: ^ Condition Ready is not True (False) 9:07:44PM: ok: reconcile deployment/cf-blobstore-minio (apps/v1) namespace: cf-blobstore 9:07:44PM: ---- waiting on 1 changes [244/245 done] ---- 9:07:47PM: ongoing: reconcile deployment/capi-api-server (apps/v1) namespace: cf-system 9:07:47PM: ^ Waiting for 1 unavailable replicas 9:07:47PM: L ok: waiting on replicaset/capi-api-server-bd668b897 (apps/v1) namespace: cf-system 9:07:47PM: L ok: waiting on pod/capi-api-server-bd668b897-cprlv (v1) namespace: cf-system 9:07:47PM: L ongoing: waiting on pod/capi-api-server-bd668b897-7drpp (v1) namespace: cf-system 9:07:47PM: ^ Condition Ready is not True (False) 9:07:57PM: ok: reconcile deployment/capi-api-server (apps/v1) namespace: cf-system 9:07:57PM: ---- applying complete [245/245 done] ---- 9:07:57PM: ---- waiting complete [245/245 done] ---- Succeeded ``` インストール後の`Pod`一覧は次の通りです。 ``` $ kubectl get pod -A NAMESPACE NAME READY STATUS RESTARTS AGE cf-blobstore cf-blobstore-minio-6745578955-nz8bf 2/2 Running 0 4m43s cf-db cf-db-postgresql-0 2/2 Running 0 4m53s cf-system capi-api-server-bd668b897-7drpp 5/5 Running 2 4m45s cf-system capi-api-server-bd668b897-cprlv 5/5 Running 3 4m45s cf-system capi-clock-76d55f5dc9-kqjnk 2/2 Running 1 4m55s cf-system capi-deployment-updater-6b8bddb85b-m2fds 2/2 Running 1 4m53s cf-system capi-kpack-watcher-598bf58c77-gbjfb 2/2 Running 0 4m54s cf-system capi-worker-8bc56859d-jtdlw 2/2 Running 1 4m53s cf-system cfroutesync-785c568d7b-krrvn 2/2 Running 0 4m43s cf-system eirini-7d5b6f65cb-ndjwf 2/2 Running 0 4m44s cf-system fluentd-d2zlm 2/2 Running 0 4m54s cf-system log-cache-9cb8b6bd9-5fzb9 5/5 Running 2 4m44s cf-system metric-proxy-6db4567cf9-jmcmh 2/2 Running 0 4m43s cf-system uaa-79bdb97476-xnwcz 2/2 Running 0 4m42s istio-system istio-citadel-6c7788b-5cjm8 1/1 Running 0 6m24s istio-system istio-galley-59647cbf86-jv7s7 2/2 Running 0 6m24s istio-system istio-ingressgateway-ldb72 2/2 Running 0 6m istio-system istio-pilot-6cf5468446-wkrzg 2/2 Running 0 6m23s istio-system istio-policy-6858f85497-kxw6n 2/2 Running 2 6m23s istio-system istio-sidecar-injector-6647645d86-xlbcw 1/1 Running 0 6m24s istio-system istio-telemetry-f84bd7d77-kjjrq 2/2 Running 1 6m23s kpack kpack-controller-559cd7f665-p6txb 1/1 Running 0 6m27s kpack kpack-webhook-5bdfdf487c-vv5vr 1/1 Running 0 6m26s kube-system coredns-6955765f44-n4qzd 1/1 Running 0 29m kube-system coredns-6955765f44-thqj8 1/1 Running 0 29m kube-system etcd-kind-control-plane 1/1 Running 0 29m kube-system kindnet-s9l7m 1/1 Running 0 29m kube-system kube-apiserver-kind-control-plane 1/1 Running 0 29m kube-system kube-controller-manager-kind-control-plane 1/1 Running 0 29m kube-system kube-proxy-jfbm8 1/1 Running 0 29m kube-system kube-scheduler-kind-control-plane 1/1 Running 0 29m local-path-storage local-path-provisioner-7745554f7f-vnwh9 1/1 Running 0 29m metacontroller metacontroller-0 2/2 Running 0 4m53s ``` インストール後の`Service`一覧は次の通りです。`istio-ingressgateway`が`NodePort`になっており、`31080`->`80`、`31443`->`443`になっていることに注目してください。 Kindの設定内容と一致します。 ``` $ kubectl get svc -A NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE cf-blobstore cf-blobstore-minio ClusterIP 10.96.78.163 9000/TCP 6m34s cf-db cf-db-postgresql ClusterIP 10.96.218.112 5432/TCP 6m32s cf-db cf-db-postgresql-headless ClusterIP None 5432/TCP 6m32s cf-system capi ClusterIP 10.96.131.69 80/TCP 6m34s cf-system cfroutesync ClusterIP 10.96.8.232 80/TCP 6m34s cf-system eirini ClusterIP 10.96.99.214 8085/TCP 6m34s cf-system log-cache ClusterIP 10.96.95.99 8083/TCP 6m34s cf-system log-cache-syslog ClusterIP 10.96.207.232 8082/TCP 6m34s cf-system metric-proxy ClusterIP 10.96.76.205 8080/TCP 6m34s cf-system uaa ClusterIP 10.96.43.61 8080/TCP 6m32s default kubernetes ClusterIP 10.96.0.1 443/TCP 29m istio-system istio-citadel ClusterIP 10.96.221.120 8060/TCP,15014/TCP 6m34s istio-system istio-galley ClusterIP 10.96.55.132 443/TCP,15014/TCP,9901/TCP,15019/TCP 6m34s istio-system istio-ingressgateway NodePort 10.96.33.9 15020:32508/TCP,80:31080/TCP,443:31443/TCP,15029:32477/TCP,15030:30356/TCP,15031:30882/TCP,15032:31281/TCP,15443:30490/TCP 6m33s istio-system istio-pilot ClusterIP 10.96.100.89 15010/TCP,15011/TCP,8080/TCP,15014/TCP 6m33s istio-system istio-policy ClusterIP 10.96.107.158 9091/TCP,15004/TCP,15014/TCP 6m33s istio-system istio-sidecar-injector ClusterIP 10.96.157.123 443/TCP 6m33s istio-system istio-telemetry ClusterIP 10.96.3.64 9091/TCP,15004/TCP,15014/TCP,42422/TCP 6m32s kpack kpack-webhook ClusterIP 10.96.104.123 443/TCP 6m34s kube-system kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP,9153/TCP kube-system metrics-server ClusterIP 10.96.161.224 443/TCP 3m34s ``` インストール後の`PersistentVolume`一覧は次の通りです。データベースとしてPostgreSQL、BlobstoreとしてMinioが`PersistentVolume`を使用しています。 ``` $ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-dd2c1c7d-f741-4f9a-bd4a-b450baa24046 8Gi RWO Delete Bound cf-db/data-cf-db-postgresql-0 standard 5m33s pvc-dea38d71-286c-415d-9754-a252deb94a59 10Gi RWO Delete Bound cf-blobstore/cf-blobstore-minio standard 5m19s ``` `kapp`を使ってインストールした場合は`kapp inspect -a <アプリ名> --tree`コマンドで、作成されたリソース一覧を確認できます。 次のエンドポイントにアクセスして、Cloud Controllerのバージョンを確認できます。 ``` $ curl -s -k https://api.local.maki.lol/v2/info | jq . { "name": "", "build": "", "support": "", "version": 0, "description": "", "authorization_endpoint": "https://login.local.maki.lol", "token_endpoint": "https://uaa.local.maki.lol", "min_cli_version": "", "min_recommended_cli_version": "", "app_ssh_endpoint": "TODO.TODO", "app_ssh_host_key_fingerprint": "placeholder", "app_ssh_oauth_client": "placeholder", "doppler_logging_endpoint": "wss://doppler.local.maki.lol:443", "api_version": "2.148.0", "osbapi_version": "2.15", "routing_endpoint": "https://api.local.maki.lol/routing" } ``` ### Cloud Foundryにログイン 早速Cloud Foundryにログインしてみます。 `admin`ユーザーのパスワードは`bosh int /tmp/cf-values.yml --path /cf_admin_password`で取得できます。 次のコマンドでログインします。 ``` cf login -a api.local.maki.lol -u admin -p $(bosh int /tmp/cf-values.yml --path /cf_admin_password) --skip-ssl-validation ``` 次のようなログが出力されればOKです。 ``` API endpoint: api.local.maki.lol Authenticating... OK Targeted org system API endpoint: https://api.local.maki.lol (API version: 3.83.0) User: admin Org: system Space: No space targeted, use 'cf target -s SPACE' ``` Docker Imageをそのままデプロイできる機能を有効にします。0.1.0ではBuildpackを使う場合はもこの設定が必要です。 ``` $ cf enable-feature-flag diego_docker Setting status of diego_docker as admin... OK Feature diego_docker Enabled. ``` UAAにアクセスしてみます。URLは https://uaa.local.maki.lol です。 ![image](https://user-images.githubusercontent.com/106908/79457457-36d37c00-802b-11ea-9e6c-c1000a91a9d8.png) ### Org、Spaceの作成 `demo` Orgと`demo` Spaceを作成します。 ``` cf create-org demo cf create-space demo -o demo cf target -o demo -s demo ``` ### Javaアプリケーションのデプロイ Spring Bootのアプリをデプロイします。 雛形プロジェクトを作成し、ビルドします。 ``` cd /tmp curl https://start.spring.io/starter.tgz \ -d artifactId=hello-cf \ -d baseDir=hello-cf \ -d dependencies=web,actuator \ -d packageName=com.example \ -d applicationName=HelloCfApplication | tar -xzvf - cd hello-cf ./mvnw clean package -DskipTests=true ``` `cf push`します。 ``` $ cf push hello -p target/hello-cf-0.0.1-SNAPSHOT.jar Pushing app hello to org demo / space demo as admin... Getting app info... Creating app with these attributes... + name: hello path: /private/tmp/hello-cf/target/hello-cf-0.0.1-SNAPSHOT.jar routes: + hello.local.maki.lol Creating app hello... Mapping routes... Comparing local files to remote cache... Packaging files to upload... Uploading files... 315.39 KiB / 315.39 KiB [===========================================================================================================================================================] 100.00% 1s Waiting for API to complete processing files... Staging app and tracing logs... Waiting for app to start... name: hello requested state: started isolation segment: placeholder routes: hello.local.maki.lol last uploaded: Thu 16 Apr 23:37:16 JST 2020 stack: buildpacks: type: web instances: 1/1 memory usage: 1024M state since cpu memory disk details #0 running 2020-04-16T14:37:26Z 0.0% 0 of 1G 0 of 1G ``` デプロイが成功しました。 `cf apps`コマンドでアプリケーション一覧を確認します。 ``` $ cf apps Getting apps in org demo / space demo as admin... OK name requested state instances memory disk urls hello started 1/1 1G 1G hello.local.maki.lol ``` `cf app`コマンドでアプリの詳細を確認できます。 ``` $ cf app hello Showing health and status for app hello in org demo / space demo as admin... name: hello requested state: started isolation segment: placeholder routes: hello.local.maki.lol last uploaded: Thu 16 Apr 23:37:16 JST 2020 stack: buildpacks: type: web instances: 1/1 memory usage: 1024M state since cpu memory disk details #0 running 2020-04-16T14:37:26Z 0.0% 0 of 1G 0 of 1G ``` `/actuator/health`エンドポイントにアクセスします。 ``` $ curl http://hello.local.maki.lol/actuator/health {"status":"UP"} ``` 0.1.0ではHTTPエンドポイントだけ利用可能で、HTTPSやTCPは使えません。 また、これまでのCloud FoundryではBuildpack v2が使用されていましたが、cf-for-k8sでは[kpack](https://github.com/pivotal/kpack)経由で[Cloud Native Buildpacks](https://buildpacks.io/)が使用されます。 `cf push`で作成されたコンテナイメージはインストール時に設定したDocker Registryにデプロイされます。実際にDockerHubにイメージがデプロイされていました。 ![image](https://user-images.githubusercontent.com/106908/79461235-d9422e00-8030-11ea-945d-fbbeddbb7a54.png) なお、Kpackが使用するCloud Native Buildpacks一覧は`kubectl get builder -n cf-workloads-staging cf-autodetect-builder -o yaml`で確認っできます。 現時点では言語として、Java, Node.js, .NET, Goが利用できます。(Builderとして`cloudfoundry/cnb:0.0.55-bionic`が登録されています。) `cf logs hello --recent`コマンドでログを確認できます。Cloud Native Buildpacksの実行結果が出力されています。 cf-for-k8sでは、EiriniというコンポーネントがCloud Controllerからのリクエストを受けてKubernetesにアプリを`Statefulset`としてデプロイします。Eiriniが作成した`StatefulSet`及び、それにより作られた`Pod`は次のコマンドで確認できます。 ``` $ kubectl get statefulset,pod -n cf-workloads NAME READY AGE statefulset.apps/hello-demo-76752befbe 1/1 4m55s NAME READY STATUS RESTARTS AGE pod/hello-demo-76752befbe-0 2/2 Running 0 4m55s ``` > 現時点でcf-for-k8sでDeveloper(`cf push`を使うユーザー)が`kubectl`を使うことは想定していません。`kubectl`はPlatformエンジニアが使う想定です。 ### Smoke Testの実行 `cf push`は成功しましたが、インストールが適切にできているか確認するために、Smoke Testを実行してみます。 Smoke Testを実行するには[ginkgo](https://github.com/onsi/ginkgo)をインストールする必要があります。 ``` brew install go go get -u github.com/onsi/ginkgo/ginkgo export PATH=$PATH:$HOME/go/bin ``` 次のコマンドでSmoke Testを実行します。 ``` export SMOKE_TEST_APPS_DOMAIN=local.maki.lol export SMOKE_TEST_API_ENDPOINT=api.local.maki.lol export SMOKE_TEST_USERNAME=admin export SMOKE_TEST_PASSWORD=$(bosh int /tmp/cf-values.yml --path /cf_admin_password) export SMOKE_TEST_SKIP_SSL=true ./cf-for-k8s/hack/run-smoke-tests.sh ``` 次のような結果が出力されれば成功です。 ``` Running Suite: Smoke Tests Suite ================================ Random Seed: 1587047286 Will run 2 of 2 specs ..(略).. Ran 2 of 2 Specs in 119.501 seconds SUCCESS! -- 2 Passed | 0 Failed | 0 Pending | 0 Skipped PASS Ginkgo ran 1 suite in 2m0.870246904s Test Suite Passed ``` ### Cloud Foundryのアンインストール アンインストールは`kapp`で一発です。 ``` kapp delete -a cf ``` --- cf-for-k8s 0.1.0を試しました。 まだまだ制限は多く、Productionで利用できるレベルではないですが、少しずつ機能が追加されていくでしょう。 現時点でのKnown Issuesは次のページに記載されています。 https://github.com/cloudfoundry/cf-for-k8s/releases/tag/v0.1.0