--- title: Cartographer 0.0.6をkindで試す tags: ["Kubernetes", "Cartographer", "kpack", "Cloud Native Buildpacks", "Paketo"] categories: ["Dev", "CaaS", "Kubernetes", "Cartographer"] date: 2021-10-06T13:36:13Z updated: 2021-10-07T05:30:43Z --- "Cloud Native Supply Chains"と呼ばれる[Cartographer](https://cartographer.sh)がオープンソース化されたので、早速試してみます。 Cartographerの概要を説明した後に、今回はCartographerをkindにインストールし、PaaSのような感覚で"Source to URL"でアプリケーションを簡単デプロイできることを体験します。 **目次** ### Cartographerとは Cartographerがやってくれることを簡単にいうと、任意のk8sリソースのoutput(status)を使って次のk8sリソースに反映させるという橋渡しを行い、アプリケーションをリリースするための"Supply Chain"を提供することです。 例えばgitにpushしたソースコードをpullしてコンテナイメージを作成し、そのイメージをマニフェストに反映してデプロイするというフローを実現したい場合、 1. [Flux](https://fluxcd.io) の [GitRepository](https://fluxcd.io/docs/components/source/gitrepositories/) リソースがgitレポジトリがwatchし、変更があればソースコードをtar.gzファイルに圧縮してファイルサーバーに保存する 2. [kpack](https://github.com/pivotal/kpack) の [Image](https://github.com/pivotal/kpack/blob/main/docs/image.md) リソースが1.のURLからソースコードを取得し、 [Cloud Native Buildpacks](https://buildpacks.io) を使用してコンテナイメージを作成し、Dockerレジストリにイメージをpushする (Source to Image) 3. [Knative](https://knative.dev) の [Service](https://github.com/knative/specs/blob/main/specs/serving/knative-api-specification-1.0.md#service) リソースが2.のimageを使用してアプリケーションをデプロイする (Image to URL) という連携が考えられますが、Cartographerはこれらのリソースの変更をwatchし、↓の図のようにリソース間の値の受け渡しを自動で行います。 ![image](https://user-images.githubusercontent.com/106908/136144130-872f6bc9-ec94-4960-9e2a-a00f6f9af93b.jpeg) 例えば 1. watchしているgitリポジトリに対して新しいcommitがpushされることにより 、GitRepositoryリソースの `.status.artifact.url` が変更されれば、その値を自動でImageリソースの `.spec.source.blob.url` に設定する 2. 1.の後や、kpackの [ClusterBuilder](https://github.com/pivotal/kpack/blob/main/docs/builders.md#cluster-builders) や [ClusterStack](https://github.com/pivotal/kpack/blob/main/docs/stack.md) (OSのベースイメージ)がアップデートされることにより、Imageリソースの `.status.latestImage` が変更されれば、その値を自動でServiceリソースの `.spec.template.spec.containers[0].image` に設定する ということをCartographerが行います。 これらの組み合わせや値の受け渡し方法は自由にカスタマイズできて、下の図のように使い慣れたコンポーネントを選択して、組織にあった"Supply Chain"を定義することができます。 k8sリソースの入出力がfitすれば、どんなコンポーネントでも間に挟むことができます。例えばコンテナイメージをビルドする前にユニットテストを実行したり、イメージをビルドした後にイメージをスキャンすることもできます。 [ClusterSupplyChain](https://cartographer.sh/docs/v0.0.6/reference/#clustersupplychain) リソースにこのSupply Chainを定義できます。またSupply Chainへの入力(e.g. gitリポジトリのURLなど)を [Workload](https://cartographer.sh/docs/v0.0.6/reference/#workload) リソースに定義できます。 ![image](https://content.cdntwrk.com/files/aHViPTYzOTc1JmNtZD1pdGVtZWRpdG9yaW1hZ2UmZmlsZW5hbWU9aXRlbWVkaXRvcmltYWdlXzYxNWI4NmE0MjE0NzMucG5nJnZlcnNpb249MDAwMCZzaWc9YjMxMDdmNDZmMTIwYjhiNzFhNTY4NTg0OGE2YWIyOTc%253D) (図は https://tanzu.vmware.com/content/blog/vmware-tanzu-application-platform-beta-2-announcement より) 同じようなことをCI/CDツールを組み合わせて既に行っている組織も多いのではないかと思いますが、 Cartographerの良いところはDeveloperとOperatorの責任の分離を明確に行っている点です。 下の図のように、Operatorが定義したClusterSupplyChainを使ってDeveloperがWorkloadを定義しアプリケーションをデプロイできます。 ![image](https://user-images.githubusercontent.com/106908/136133334-872d0ce8-f4e4-4a27-8286-3aecd1c7a710.png) (図は https://cartographer.sh/docs/v0.0.6/ より) CI/CDツールの組み合わせの場合は、 "誰がマニフェストやCIパイプラインを作るのか"や"Operatorがテンプレートを配布し、Developerがそれをカスタマイズする運用をするとテンプレートの変更を反映するのが大変"という課題を解決することができます。 ### Getting Started 前置きが長くなりましたが、早速試してみます。 ここではKnativeの代わりにシンプルに標準のDeployment・Service・Ingressを使用します。Supply Chainは次の図のようになります。 ![image](https://user-images.githubusercontent.com/106908/136181993-3655c270-40b6-4d6d-b896-b57dbe7d438d.jpeg) #### kindクラスタの作成 まずはkindクラスタを作成します。[`extraPortMappings`](https://kind.sigs.k8s.io/docs/user/ingress/) を設定してLaptop上の80/443ポートを通じてIngressにアクセスできるようにします。 ``` curl -sL https://github.com/projectcontour/contour/raw/main/examples/kind/kind-expose-port.yaml > kind-expose-port.yaml kind create cluster --config kind-expose-port.yaml ``` #### コンポーネント群のインストール 今回のSupply Chainを作るために必要な次のコンポーネント群をインストールします。 * [cert-manager](https://github.com/jetstack/cert-manager) * [kpack](https://github.com/pivotal/kpack) * [Flux2 (source controller)](https://github.com/fluxcd/source-controller) * [Contour (ingress)](https://github.com/projectcontour/contour) ``` kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.4/cert-manager.yaml kubectl apply -f https://github.com/pivotal/kpack/releases/download/v0.4.0/release-0.4.0.yaml kubectl create namespace gitops-toolkit kubectl create clusterrolebinding gitops-toolkit-admin --clusterrole=cluster-admin --serviceaccount=gitops-toolkit:default kubectl apply -n gitops-toolkit -f https://github.com/fluxcd/source-controller/releases/download/v0.15.4/source-controller.crds.yaml -f https://github.com/fluxcd/source-controller/releases/download/v0.15.4/source-controller.deployment.yaml kubectl apply -f https://projectcontour.io/quickstart/contour.yaml ``` インストール後のPod一覧は次の通りです。 ``` $ kubectl get pod -A NAMESPACE NAME READY STATUS RESTARTS AGE cert-manager cert-manager-7c6f78c46d-xncwh 1/1 Running 0 77s cert-manager cert-manager-cainjector-668d9c86df-dskgc 1/1 Running 0 77s cert-manager cert-manager-webhook-764b556954-zfb7c 1/1 Running 0 77s gitops-toolkit source-controller-764686cbbd-tjpk2 1/1 Running 0 76s kpack kpack-controller-98c4fd6c7-qld5f 1/1 Running 0 77s kpack kpack-webhook-65d59b7ffd-d2x8l 1/1 Running 0 77s kube-system coredns-558bd4d5db-gjlmc 1/1 Running 0 77s kube-system coredns-558bd4d5db-xlp85 1/1 Running 0 77s kube-system etcd-kind-control-plane 1/1 Running 0 86s kube-system kindnet-zrzgv 1/1 Running 0 77s kube-system kube-apiserver-kind-control-plane 1/1 Running 0 86s kube-system kube-controller-manager-kind-control-plane 1/1 Running 0 93s kube-system kube-proxy-mq9fx 1/1 Running 0 77s kube-system kube-scheduler-kind-control-plane 1/1 Running 0 86s local-path-storage local-path-provisioner-547f784dff-qb9jx 1/1 Running 0 77s projectcontour contour-7cc4786577-gpvgn 1/1 Running 0 75s projectcontour contour-7cc4786577-pmwch 1/1 Running 0 75s projectcontour envoy-n7q6l 2/2 Running 0 66s ``` #### Cartographerのインストール 次にCartographerをインストールします。 [ドキュメント](https://cartographer.sh/docs/v0.0.6/install/) の通りにインストールしますが、 現時点のドキュメントは [Carvel](https://carvel.dev) を使った手順のみ用意されています。 この方法は [Air-gapped環境](https://carvel.dev/imgpkg/docs/latest/air-gapped-workflow/) にもインストール可能な、応用の効くやり方なのですが、少し手間がかかります。 [こちらのissue](https://github.com/vmware-tanzu/cartographer/issues/198) の通り、 `kubectl apply -f cartographer.yaml` でインストールできる方法は今度準備するようです。 ##### Carvel Toolsのインストール まずは [Carvel](https://carvel.dev/#install) のツール群をインストールします。 ``` brew tap vmware-tanzu/carvel brew install ytt kbld kapp imgpkg kwt vendir ``` あるいは ``` curl -sL https://carvel.dev/install.sh | bash ``` を実行してください。 本記事では `imgpkg`、`kbld`、`kapp` を使用します。次のバージョンで動作確認しています。 ``` $ imgpkg version imgpkg version 0.19.0 Succeeded $ kbld version kbld version 0.31.0 Succeeded $ kapp version kapp version 0.42.0 ``` ##### Carvelを使ったCartographerのインストール バージョン [0.0.6](https://github.com/vmware-tanzu/cartographer/releases/tag/v0.0.6) 時点では、Cartographerのマニフェスト及びコンテナイメージは [imgpkg](https://carvel.dev/imgpkg/docs/latest/) のtar形式で配布されています。 これはコンテナイメージを別途コンテナレジストリにrelocationする想定です。 ここではコンテナレジストリとして、GitHub Packages(ghcr.io)を使用します。 このコンテナレジストリは後ほど設定するkpackでも使用するので、ユーザー名とパスワードを環境変数に設定します。 ``` export GITHUB_USERNAME=making export GITHUB_API_TOKEN=************* docker login ghcr.io -u ${GITHUB_USERNAME} -p ${GITHUB_API_TOKEN} ``` 次のコマンドでCartographerのtarファイルをダウンロードして、`imgpkg` コマンドを使用してGitHub Packagesへrelocationします。 ``` curl -sL https://github.com/vmware-tanzu/cartographer/releases/download/v0.0.6/bundle.tar > /tmp/bundle.tar imgpkg copy --tar /tmp/bundle.tar --to-repo ghcr.io/${GITHUB_USERNAME}/cartographer-bundle --lock-output /tmp/cartographer-bundle.lock.yaml ``` 次のようなログが出力されます。 ``` copy | importing 2 images... 35.20 MiB / 35.27 MiB [===================================================================================================================================================================================================================================================] 99.80% 3.20 MiB/s 10s copy | done uploading images Succeeded ``` GitHub Packagesを確認すると `cartographer-bundle` というイメージがアップロードされていることがわかります。 ![image](https://user-images.githubusercontent.com/106908/136062122-5948e18a-cc7d-4a50-bce6-49f76c38cae1.png) 次に、次のコマンドを実行して、relocation後のimageの設定が反映されたmanifestファイル群を取得します。 ``` imgpkg pull --lock /tmp/cartographer-bundle.lock.yaml --output /tmp/cartographer ``` 次のようなログが出力されます。 ``` Pulling bundle 'ghcr.io/making/cartographer-bundle@sha256:f7e402cfa7c9404afdb51f9c6967c688e2595660b9335429ed5a880fc2caa80f' Extracting layer 'sha256:ec8f865d6051db9570e067cf3604a19face114a6d1e8920b61bae44eae64078d' (1/1) Locating image lock file images... The bundle repo (ghcr.io/making/cartographer-bundle) is hosting every image specified in the bundle's Images Lock file (.imgpkg/images.yml) Succeeded ``` 次のようなファイルが取得されます。imgpkgの [bundle形式](https://carvel.dev/imgpkg/docs/latest/resources/#bundle) です。 ``` $ find /tmp/cartographer /tmp/cartographer /tmp/cartographer/.imgpkg /tmp/cartographer/.imgpkg/images.yml /tmp/cartographer/config /tmp/cartographer/config/cartographer.yaml /tmp/cartographer/config/overlays /tmp/cartographer/config/overlays/.gitkeep /tmp/cartographer/config/objects /tmp/cartographer/config/objects/kapp-secret-ignore.yaml ``` 次のコマンドでこのmanifestをデプロイします。ここでは`kbld`と`kapp`コマンドを使用します。 ``` kubectl create namespace cartographer-system kubectl create secret -n cartographer-system docker-registry private-registry-credentials --docker-server=ghcr.io --docker-username=${GITHUB_USERNAME} --docker-password=${GITHUB_API_TOKEN} kbld -f /tmp/cartographer | kapp deploy -a cartographer -c -f - -y ``` インストールが完了すれば、次のコマンドを実行してどのようなリソースが作成されたか確認できます。 ``` $ kapp inspect -a cartographer -t Target cluster 'https://127.0.0.1:51332' (nodes: kind-control-plane) Resources in app 'cartographer' Namespace Name Kind Owner Conds. Rs Ri Age (cluster) clusterimagetemplates.carto.run CustomResourceDefinition kapp 2/2 t ok - 30s (cluster) clustersourcetemplates.carto.run CustomResourceDefinition kapp 2/2 t ok - 30s cartographer-system cartographer-webhook Certificate kapp 1/1 t ok - 29s cartographer-system L cartographer-webhook-chq25 CertificateRequest cluster 2/2 t ok - 28s (cluster) pipelines.carto.run CustomResourceDefinition kapp 2/2 t ok - 30s (cluster) clustersupplychainvalidator ValidatingWebhookConfiguration kapp - ok - 30s cartographer-system cartographer-webhook Secret kapp - ok - 30s (cluster) clustersupplychains.carto.run CustomResourceDefinition kapp 2/2 t ok - 30s (cluster) clusterconfigtemplates.carto.run CustomResourceDefinition kapp 2/2 t ok - 30s cartographer-system cartographer-webhook Service kapp - ok - 29s cartographer-system L cartographer-webhook Endpoints cluster - ok - 29s cartographer-system L cartographer-webhook-kd7mx EndpointSlice cluster - ok - 29s (cluster) clustertemplates.carto.run CustomResourceDefinition kapp 2/2 t ok - 30s (cluster) workloads.carto.run CustomResourceDefinition kapp 2/2 t ok - 30s (cluster) cartographer-cluster-admin ClusterRoleBinding kapp - ok - 30s cartographer-system cartographer-controller ServiceAccount kapp - ok - 30s cartographer-system selfsigned-issuer Issuer kapp 1/1 t ok - 29s cartographer-system cartographer-controller Deployment kapp 2/2 t ok - 29s cartographer-system L cartographer-controller-f664d5bc ReplicaSet cluster - ok - 29s cartographer-system L.. cartographer-controller-f664d5bc-vhg64 Pod cluster 4/4 t ok - 29s cartographer-system private-registry-credentials Secret kapp - ok - 30s (cluster) runtemplates.carto.run CustomResourceDefinition kapp 2/2 t ok - 30s Rs: Reconcile state Ri: Reconcile information 22 resources Succeeded ``` #### kpackの設定 次にkpackの設定を行います。 ##### imagePullSecretの設定 `default` namespaceの`default` service accountに対してghcr.ioへの`imagePullSecret`を設定しておきます。 ``` cat < dockerconfig.yaml apiVersion: v1 kind: Secret metadata: name: regsecret namespace: default type: kubernetes.io/dockerconfigjson stringData: .dockerconfigjson: | { "auths": { "https://ghcr.io": { "username": "${GITHUB_USERNAME}", "password": "${GITHUB_API_TOKEN}" } } } EOF kubectl apply -f dockerconfig.yaml kubectl patch -n default serviceaccount default -p "{\"secrets\":[{\"name\":\"regsecret\"}],\"imagePullSecrets\":[{\"name\":\"regsecret\"}]}" ``` ##### ClusterBuilderの設定 [Paketo Buildpacks](https://paketo.io) を使ったClusterBuilder及び、ClusterStore、ClusterStackを定義します。 ここではGo、Java、Node.js、Rubyのみ対応します。 ```yaml cat < clusterbuilder.yaml apiVersion: kpack.io/v1alpha1 kind: ClusterStore metadata: name: default spec: sources: - image: gcr.io/paketo-buildpacks/ruby - image: gcr.io/paketo-buildpacks/nodejs - image: gcr.io/paketo-buildpacks/go - image: gcr.io/paketo-buildpacks/java --- apiVersion: kpack.io/v1alpha1 kind: ClusterStack metadata: name: base spec: id: io.buildpacks.stacks.bionic buildImage: image: paketobuildpacks/build:base-cnb runImage: image: paketobuildpacks/run:base-cnb --- apiVersion: kpack.io/v1alpha1 kind: ClusterBuilder metadata: name: base spec: serviceAccountRef: name: default namespace: default tag: ghcr.io/${GITHUB_USERNAME}/clusterbuilder:base stack: name: base kind: ClusterStack store: name: default kind: ClusterStore order: - group: - id: paketo-buildpacks/ruby - group: - id: paketo-buildpacks/nodejs - group: - id: paketo-buildpacks/go - group: - id: paketo-buildpacks/java EOF kubectl apply -f clusterbuilder.yaml ``` しばらくするとClusterBuilderに対応するbuilderのイメージがアップロードされます。 ``` $ kubectl get clusterbuilder NAME LATESTIMAGE READY base ghcr.io/making/clusterbuilder:base@sha256:c3640f0f6e1643e692d7f2abacaee766dfb7f76fa84adc1bdc6ecdc5dcc29cfa True ``` GitHub Packagesでそのイメージを確認できます。 ![image](https://user-images.githubusercontent.com/106908/136072771-54443aa5-21a4-42d1-b9ab-b242e6561cf2.png) > ⚠️ GitHub PackagesのFreeプランを使用する場合、private repositoryに対するストーレジと転送量の制約があるため、場合によってはpublic repositoryへ変更した方が良いかもしれません。 #### Supply Chainの設定 いよいよCartographerのSupply Chainを定義します。再掲になりますが、次のようなSupply Chainを作成します。 ![image](https://user-images.githubusercontent.com/106908/136181993-3655c270-40b6-4d6d-b896-b57dbe7d438d.jpeg) CartographerではSupply Chainを構成するテンプレートとして次の4種類を利用できます。 * [ClusterSourceTemplate](https://cartographer.sh/docs/v0.0.6/reference/#clustersourcetemplate) ... outputがソースコードの情報(urlとrevision)であるk8sリソースのテンプレート定義 * [ClusterImageTemplate](https://cartographer.sh/docs/v0.0.6/reference/#clusterimagetemplate) ... outputがコンテナイメージの情報(image name)であるk8sリソースのテンプレート定義 * [ClusterConfigTemplate](https://cartographer.sh/docs/v0.0.6/reference/#clusterconfigtemplate) ... outputが修正されたconfigであるk8sリソースのテンプレート定義 * [ClusterTemplate](https://cartographer.sh/docs/v0.0.6/reference/#clustertemplate) ... outputを必要としないk8sリソースのテンプレート定義 上記の例では * GitRepositoryリソースのテンプレート定義 -> ClusterSourceTemplate * Imageリソースのテンプレート定義 -> ClusterImageTemplate * Deploy, Service, Ingressリソースのテンプレート定義 -> ClusterTemplate に対応します。 ##### Templatesの作成 各種テンプレートを次のように作成します。 ```yaml cat <<'EOF' | sed "s/CHANGE_ME/${GITHUB_USERNAME}/" > supply-chain-templates.yaml apiVersion: carto.run/v1alpha1 kind: ClusterSourceTemplate metadata: name: source spec: urlPath: .status.artifact.url revisionPath: .status.artifact.revision template: apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: GitRepository metadata: name: $(workload.metadata.name)$ labels: app.kubernetes.io/part-of: $(workload.metadata.name)$ spec: interval: 3m url: $(workload.spec.source.git.url)$ ref: $(workload.spec.source.git.ref)$ ignore: "" --- apiVersion: carto.run/v1alpha1 kind: ClusterImageTemplate metadata: name: image spec: imagePath: .status.latestImage template: apiVersion: kpack.io/v1alpha1 kind: Image metadata: name: $(workload.metadata.name)$ labels: app.kubernetes.io/part-of: $(workload.metadata.name)$ spec: tag: ghcr.io/CHANGE_ME/$(workload.metadata.name)$ serviceAccount: default builder: kind: ClusterBuilder name: base source: blob: url: $(sources.source.url)$ --- apiVersion: carto.run/v1alpha1 kind: ClusterTemplate metadata: name: app-deploy-deployment spec: template: apiVersion: apps/v1 kind: Deployment metadata: name: $(workload.metadata.name)$ labels: app.kubernetes.io/part-of: $(workload.metadata.name)$ spec: template: metadata: labels: app.kubernetes.io/part-of: $(workload.metadata.name)$ spec: containers: - name: workload image: $(images.image.image)$ env: $(workload.spec.env)$ resources: $(workload.spec.resources)$ ports: - name: http-port containerPort: 8080 securityContext: runAsUser: 1000 selector: matchLabels: app.kubernetes.io/part-of: $(workload.metadata.name)$ --- apiVersion: carto.run/v1alpha1 kind: ClusterTemplate metadata: name: app-deploy-service spec: template: apiVersion: v1 kind: Service metadata: name: $(workload.metadata.name)$ labels: app.kubernetes.io/part-of: $(workload.metadata.name)$ spec: ports: - name: http port: 80 protocol: TCP targetPort: 8080 selector: app.kubernetes.io/part-of: $(workload.metadata.name)$ type: ClusterIP --- apiVersion: carto.run/v1alpha1 kind: ClusterTemplate metadata: name: app-deploy-ingress spec: template: apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: $(workload.metadata.name)$ labels: app.kubernetes.io/part-of: $(workload.metadata.name)$ spec: rules: - host: $(workload.metadata.name)$-127-0-0-1.sslip.io http: paths: - backend: service: name: $(workload.metadata.name)$ port: number: 80 path: / pathType: Exact EOF kubectl apply -f supply-chain-templates.yaml ``` ##### SupplyChainの定義 定義したテンプレートを組み合わせたSupply ChainをClusterSupplyChainリソースとして次のように定義します。 ```yaml cat <<'EOF' > supply-chain.yaml apiVersion: carto.run/v1alpha1 kind: ClusterSupplyChain metadata: name: supply-chain spec: selector: app.tanzu.vmware.com/workload-type: web components: - name: source-provider templateRef: kind: ClusterSourceTemplate name: source - name: image-builder templateRef: kind: ClusterImageTemplate name: image sources: - component: source-provider name: source - name: deployer-deployment templateRef: kind: ClusterTemplate name: app-deploy-deployment images: - component: image-builder name: image - name: deployer-service templateRef: kind: ClusterTemplate name: app-deploy-service - name: deployer-ingress templateRef: kind: ClusterTemplate name: app-deploy-ingress EOF kubectl apply -f supply-chain.yaml ``` ここまではOperatorの役目です。 #### Workloadのデプロイ このSupply Chainを使って、いよいよアプリケーションをデプロイします。ここからはDeveloperの役目です。 ##### Goアプリのデプロイ まずはGoのアプリをデプロイします。デプロイするサンプルアプリとして https://github.com/making/hello-golang を使用します。 次のWorkloadを作成します。Developerとして定義する内容はこれだけです。どのようにコンテナイメージが作られてどのようにk8sへデプロイするかを意識する必要がありません。 ```yaml cat < hello-golang.yaml apiVersion: carto.run/v1alpha1 kind: Workload metadata: labels: app.tanzu.vmware.com/workload-type: web name: hello-golang spec: source: git: url: https://github.com/making/hello-golang.git ref: branch: master env: - name: TARGET value: World resources: {} EOF kubectl apply -f hello-golang.yaml ``` 実際にどのような処理が行われているかをログで確認します。複数のコンテナで処理が行われるので [stern](https://github.com/stern/stern) を使用すると良いです。 ソースコード(tar.gz)が取得され、そのソースコードがGoのものであることが検出され、ビルドが行われて、イメージがpushされ、その後アプリケーションが起動していることがわかります。 ![workload-demo](https://user-images.githubusercontent.com/106908/136251374-f4f2c738-6f39-4ddb-aa2f-8d3ec8ed2612.gif) ``` $ stern 'hello-golang.*' + hello-golang-build-1-rqzsd-build-pod › prepare hello-golang-build-1-rqzsd-build-pod prepare Build reason(s): CONFIG hello-golang-build-1-rqzsd-build-pod prepare CONFIG: hello-golang-build-1-rqzsd-build-pod prepare resources: {} hello-golang-build-1-rqzsd-build-pod prepare - source: {} hello-golang-build-1-rqzsd-build-pod prepare + source: hello-golang-build-1-rqzsd-build-pod prepare + blob: hello-golang-build-1-rqzsd-build-pod prepare + url: http://source-controller.gitops-toolkit.svc.cluster.local./gitrepository/default/hello-golang/1f8f29d92011f329b695223a35bf3f480c05f8a2.tar.gz hello-golang-build-1-rqzsd-build-pod prepare Loading secret for "https://ghcr.io" from secret "regsecret" at location "/var/build-secrets/regsecret" hello-golang-build-1-rqzsd-build-pod prepare Downloading source-controller.gitops-toolkit.svc.cluster.local./gitrepository/default/hello-golang/1f8f29d92011f329b695223a35bf3f480c05f8a2.tar.gz... hello-golang-build-1-rqzsd-build-pod prepare Successfully downloaded source-controller.gitops-toolkit.svc.cluster.local./gitrepository/default/hello-golang/1f8f29d92011f329b695223a35bf3f480c05f8a2.tar.gz in path "/workspace" - hello-golang-build-1-rqzsd-build-pod › prepare + hello-golang-build-1-rqzsd-build-pod › detect hello-golang-build-1-rqzsd-build-pod detect 4 of 7 buildpacks participating hello-golang-build-1-rqzsd-build-pod detect paketo-buildpacks/ca-certificates 2.3.2 hello-golang-build-1-rqzsd-build-pod detect paketo-buildpacks/go-dist 0.6.0 hello-golang-build-1-rqzsd-build-pod detect paketo-buildpacks/go-mod-vendor 0.3.1 hello-golang-build-1-rqzsd-build-pod detect paketo-buildpacks/go-build 0.4.1 - hello-golang-build-1-rqzsd-build-pod › detect + hello-golang-build-1-rqzsd-build-pod › analyze hello-golang-build-1-rqzsd-build-pod analyze Previous image with name "ghcr.io/making/hello-golang" not found - hello-golang-build-1-rqzsd-build-pod › analyze + hello-golang-build-1-rqzsd-build-pod › build hello-golang-build-1-rqzsd-build-pod build hello-golang-build-1-rqzsd-build-pod build Paketo CA Certificates Buildpack 2.3.2 hello-golang-build-1-rqzsd-build-pod build https://github.com/paketo-buildpacks/ca-certificates hello-golang-build-1-rqzsd-build-pod build Launch Helper: Contributing to layer hello-golang-build-1-rqzsd-build-pod build Creating /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper hello-golang-build-1-rqzsd-build-pod build Paketo Go Distribution Buildpack 0.6.0 hello-golang-build-1-rqzsd-build-pod build Resolving Go version hello-golang-build-1-rqzsd-build-pod build Candidate version sources (in priority order): hello-golang-build-1-rqzsd-build-pod build go.mod -> ">= 1.16" hello-golang-build-1-rqzsd-build-pod build -> "" hello-golang-build-1-rqzsd-build-pod build hello-golang-build-1-rqzsd-build-pod build Selected Go version (using go.mod): 1.17 hello-golang-build-1-rqzsd-build-pod build hello-golang-build-1-rqzsd-build-pod build Executing build process hello-golang-build-1-rqzsd-build-pod build Installing Go 1.17 hello-golang-build-1-rqzsd-build-pod build Completed in 7.806s hello-golang-build-1-rqzsd-build-pod build hello-golang-build-1-rqzsd-build-pod build Paketo Go Mod Vendor Buildpack 0.3.1 hello-golang-build-1-rqzsd-build-pod build Checking module graph hello-golang-build-1-rqzsd-build-pod build Running 'go mod graph' hello-golang-build-1-rqzsd-build-pod build Completed in 6ms hello-golang-build-1-rqzsd-build-pod build hello-golang-build-1-rqzsd-build-pod build Skipping build process: module graph is empty hello-golang-build-1-rqzsd-build-pod build hello-golang-build-1-rqzsd-build-pod build Paketo Go Build Buildpack 0.4.1 hello-golang-build-1-rqzsd-build-pod build Executing build process hello-golang-build-1-rqzsd-build-pod build Running 'go build -o /layers/paketo-buildpacks_go-build/targets/bin -buildmode pie .' hello-golang-build-1-rqzsd-build-pod build Completed in 15.708s hello-golang-build-1-rqzsd-build-pod build hello-golang-build-1-rqzsd-build-pod build Assigning launch processes: hello-golang-build-1-rqzsd-build-pod build web: /layers/paketo-buildpacks_go-build/targets/bin/hello-golang hello-golang-build-1-rqzsd-build-pod build hello-golang: /layers/paketo-buildpacks_go-build/targets/bin/hello-golang hello-golang-build-1-rqzsd-build-pod build - hello-golang-build-1-rqzsd-build-pod › build + hello-golang-build-1-rqzsd-build-pod › export hello-golang-build-1-rqzsd-build-pod export Adding layer 'paketo-buildpacks/ca-certificates:helper' hello-golang-build-1-rqzsd-build-pod export Adding layer 'paketo-buildpacks/go-build:targets' hello-golang-build-1-rqzsd-build-pod export Adding 1/1 app layer(s) hello-golang-build-1-rqzsd-build-pod export Adding layer 'launcher' hello-golang-build-1-rqzsd-build-pod export Adding layer 'config' hello-golang-build-1-rqzsd-build-pod export Adding layer 'process-types' hello-golang-build-1-rqzsd-build-pod export Adding label 'io.buildpacks.lifecycle.metadata' hello-golang-build-1-rqzsd-build-pod export Adding label 'io.buildpacks.build.metadata' hello-golang-build-1-rqzsd-build-pod export Adding label 'io.buildpacks.project.metadata' hello-golang-build-1-rqzsd-build-pod export Setting default process type 'web' hello-golang-build-1-rqzsd-build-pod export Saving ghcr.io/making/hello-golang... hello-golang-build-1-rqzsd-build-pod export *** Images (sha256:9cfb82e456bdff7e0b2dea85b48235da56b12667a52fb865de9067132fb2071a): hello-golang-build-1-rqzsd-build-pod export ghcr.io/making/hello-golang hello-golang-build-1-rqzsd-build-pod export ghcr.io/making/hello-golang:b1.20211006.005809 hello-golang-build-1-rqzsd-build-pod export Adding cache layer 'paketo-buildpacks/go-dist:go' hello-golang-build-1-rqzsd-build-pod export Adding cache layer 'paketo-buildpacks/go-build:gocache' - hello-golang-build-1-rqzsd-build-pod › export + hello-golang-566c6c75c7-b6tdr › workload hello-golang-566c6c75c7-b6tdr workload 2021/10/06 00:59:38 helloworld: starting server... hello-golang-566c6c75c7-b6tdr workload 2021/10/06 00:59:38 helloworld: listening on port 8080 ``` このWorkloadからSupply Chainを経由して作成されるリソースを次のコマンドで確認します。 ``` $ kubectl get workload,deploy,pod,image,build,gitrepo,service,ingress NAME AGE workload.carto.run/hello-golang 2m31s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/hello-golang 1/1 1 1 61s NAME READY STATUS RESTARTS AGE pod/hello-golang-566c6c75c7-b6tdr 1/1 Running 0 61s pod/hello-golang-build-1-rqzsd-build-pod 0/1 Completed 0 2m25s NAME LATESTIMAGE READY image.kpack.io/hello-golang ghcr.io/making/hello-golang@sha256:9cfb82e456bdff7e0b2dea85b48235da56b12667a52fb865de9067132fb2071a True NAME IMAGE SUCCEEDED build.kpack.io/hello-golang-build-1-rqzsd ghcr.io/making/hello-golang@sha256:9cfb82e456bdff7e0b2dea85b48235da56b12667a52fb865de9067132fb2071a True NAME URL READY STATUS AGE gitrepository.source.toolkit.fluxcd.io/hello-golang https://github.com/making/hello-golang.git True Fetched revision: master/1f8f29d92011f329b695223a35bf3f480c05f8a2 2m31s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/hello-golang ClusterIP 10.96.31.196 80/TCP 61s service/kubernetes ClusterIP 10.96.0.1 443/TCP 7h54m NAME  CLASS HOSTS ADDRESS PORTS AGE ingress.networking.k8s.io/hello-golang hello-golang-127-0-0-1.sslip.io 80 61s ``` IngressのURL( http://hello-golang-127-0-0-1.sslip.io )にアクセスします。 ``` $ curl http://hello-golang-127-0-0-1.sslip.io Hello World! ``` "Hello World!"が返りました。 WorkloadにはソースコードのURLしか書いていないですが、アプリがURLでアクセスなところまで用意されました。 これはPaaSで実現されていた"Source to URL"に近い体験です。 ここでは割愛しますが、ソースコードを変更してgit pushすれば新しいイメージが作成されて、再デプロイされます。 Workloadを削除すれば、各種リソースも削除されます。 ``` kubectl delete -f hello-golang.yaml ``` ##### Javaアプリのデプロイ 次にJavaのアプリをデプロイします。デプロイするサンプルアプリとして https://github.com/tanzu-japan/hello-tanzu を使用します。 次のWorkloadを作成します。 ```yaml cat < hello-tanzu.yaml apiVersion: carto.run/v1alpha1 kind: Workload metadata: labels: app.tanzu.vmware.com/workload-type: web name: hello-tanzu spec: source: git: url: https://github.com/tanzu-japan/hello-tanzu.git ref: branch: main env: [] resources: {} EOF kubectl apply -f hello-tanzu.yaml ``` 同様にsternでログを確認すれば、ソースコード取得後Mavenによるビルドが行われ、イメージ作成後にデプロイされてTomcatが起動していることがわかります。 なお、Mavenによるビルドは2回目移行はキャッシュされます。 ``` stern 'hello-tanzu.*' ``` ログは[こちら](https://gist.github.com/making/4fd4dda55b097938095cbcf1a505c24a) このWorkloadからSupply Chainを経由して作成されるリソースを次のコマンドで確認します。 ``` $ kubectl get workload,deploy,pod,image,build,gitrepo,service,ingress NAME AGE workload.carto.run/hello-tanzu 12m NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/hello-tanzu 1/1 1 1 9m43s NAME READY STATUS RESTARTS AGE pod/hello-tanzu-54dd5899f4-hsxb6 1/1 Running 0 9m43s pod/hello-tanzu-build-1-fvt6g-build-pod 0/1 Completed 0 11m NAME LATESTIMAGE READY image.kpack.io/hello-tanzu ghcr.io/making/hello-tanzu@sha256:ab5c70080c2b8a73b67d90b1255a1f92a7a6261d03cf35f5812457214b00c626 True NAME IMAGE SUCCEEDED build.kpack.io/hello-tanzu-build-1-fvt6g ghcr.io/making/hello-tanzu@sha256:ab5c70080c2b8a73b67d90b1255a1f92a7a6261d03cf35f5812457214b00c626 True NAME URL READY STATUS AGE gitrepository.source.toolkit.fluxcd.io/hello-tanzu https://github.com/tanzu-japan/hello-tanzu.git Unknown reconciliation in progress 12m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/hello-tanzu ClusterIP 10.96.96.239 80/TCP 9m43s service/kubernetes ClusterIP 10.96.0.1 443/TCP 8h NAME CLASS HOSTS ADDRESS PORTS AGE ingress.networking.k8s.io/hello-tanzu hello-tanzu-127-0-0-1.sslip.io 80 9m43s ``` IngressのURL( http://hello-tanzu-127-0-0-1.sslip.io )にブラウザでアクセスして動作確認します。 ![image](https://user-images.githubusercontent.com/106908/136128060-004f3a9f-1aed-4dd6-b573-7250360f724f.png) Workloadを削除します。 ``` kubectl delete -f hello-tanzu.yaml ``` ##### Node.jsアプリのデプロイ 次にNode.jsのアプリをデプロイします。デプロイするサンプルアプリとして https://github.com/making/hello-nodejs を使用します。 次のWorkloadを作成します。 ```yaml cat < hello-nodejs.yaml apiVersion: carto.run/v1alpha1 kind: Workload metadata: name: hello-nodejs labels: app.tanzu.vmware.com/workload-type: web spec: source: git: url: https://github.com/making/hello-nodejs ref: branch: master EOF kubectl apply -f hello-nodejs.yaml ``` 同様にsternでログを確認すれば、ソースコード取得後npmによるビルドが行われていることがわかります。 なお、npmによるビルドは2回目移行はキャッシュされます。 ``` stern 'hello-nodejs.*' ``` ログは[こちら](https://gist.github.com/making/9bdb2bc5806332d0efb54473fca4d068) ``` $ kubectl get workload,deploy,pod,image,build,gitrepo,service,ingress NAME AGE workload.carto.run/hello-nodejs 7m18s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/hello-nodejs 1/1 1 1 6m23s NAME READY STATUS RESTARTS AGE pod/hello-nodejs-7f87556847-kk4bk 1/1 Running 0 6m23s pod/hello-nodejs-build-1-qxxwq-build-pod 0/1 Completed 0 7m12s NAME LATESTIMAGE READY image.kpack.io/hello-nodejs ghcr.io/making/hello-nodejs@sha256:b11ec565f737dda90a76cbfa87aae92cdc348fccdf36de1d0b387c229cb5e4df True NAME IMAGE SUCCEEDED build.kpack.io/hello-nodejs-build-1-qxxwq ghcr.io/making/hello-nodejs@sha256:b11ec565f737dda90a76cbfa87aae92cdc348fccdf36de1d0b387c229cb5e4df True NAME URL READY STATUS AGE gitrepository.source.toolkit.fluxcd.io/hello-nodejs https://github.com/making/hello-nodejs True Fetched revision: master/9b066f581bd86f6580b73209439bd5cb4b3af523 7m18s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/hello-nodejs ClusterIP 10.96.88.240 80/TCP 6m23s service/kubernetes ClusterIP 10.96.0.1 443/TCP 8h NAME CLASS HOSTS ADDRESS PORTS AGE ingress.networking.k8s.io/hello-nodejs hello-nodejs-127-0-0-1.sslip.io 80 6m23s ``` IngressのURL( http://hello-nodejs-127-0-0-1.sslip.io )にcurlでアクセスして動作確認します。 ``` $ curl http://hello-nodejs-127-0-0-1.sslip.io Hello World! ``` Workloadを削除します。 ``` kubectl delete -f hello-nodejs.yaml ``` ##### Rubyアプリのデプロイ 次にRubyのアプリをデプロイします。デプロイするサンプルアプリとして https://github.com/making/hello-ruby を使用します。 次のWorkloadを作成します。 ```yaml cat < hello-ruby.yaml apiVersion: carto.run/v1alpha1 kind: Workload metadata: name: hello-ruby labels: app.tanzu.vmware.com/workload-type: web spec: source: git: url: https://github.com/making/hello-ruby ref: branch: main env: - name: PORT value: "8080" EOF kubectl apply -f hello-ruby.yaml ``` 同様にsternでログを確認します。 ``` stern 'hello-ruby.*' ``` ログは[こちら](https://gist.github.com/making/a97d99d6aa8cbc2513a65a109a9c8389) ``` $ kubectl get workload,deploy,pod,image,build,gitrepo,service,ingress NAME AGE workload.carto.run/hello-ruby 8m7s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/hello-ruby 1/1 1 1 7m27s NAME READY STATUS RESTARTS AGE pod/hello-ruby-5cbcd9546f-xcf7g 1/1 Running 0 7m27s pod/hello-ruby-build-1-9nmz8-build-pod 0/1 Completed 0 8m1s NAME LATESTIMAGE READY image.kpack.io/hello-ruby ghcr.io/making/hello-ruby@sha256:5c2bcd9182a62c9fcb191f2f1d9639f0eb86836943093a553d9b00d363223cfe True NAME IMAGE SUCCEEDED build.kpack.io/hello-ruby-build-1-9nmz8 ghcr.io/making/hello-ruby@sha256:5c2bcd9182a62c9fcb191f2f1d9639f0eb86836943093a553d9b00d363223cfe True NAME URL READY STATUS AGE gitrepository.source.toolkit.fluxcd.io/hello-ruby https://github.com/making/hello-ruby True Fetched revision: main/b259d9f2bd6f7da6b0fc266f1d8bb6db56a199fd 8m7s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/hello-ruby ClusterIP 10.96.117.16 80/TCP 7m27s service/kubernetes ClusterIP 10.96.0.1 443/TCP 9h NAME CLASS HOSTS ADDRESS PORTS AGE ingress.networking.k8s.io/hello-ruby hello-ruby-127-0-0-1.sslip.io 80 7m27s ``` IngressのURL( http://hello-ruby-127-0-0-1.sslip.io )にcurlでアクセスして動作確認します。 ``` $ curl http://hello-ruby-127-0-0-1.sslip.io Hello World! ``` Workloadを削除します。 ``` kubectl delete -f hello-ruby.yaml ``` --- Cartographer 0.0.6をkindにインストールして様々なアプリケーションをデプロイしました。 Cartographerの面白さを少しは感じてもらえたのではないでしょうか。 次はKnativeやTektonとの連携を試そうと思います。 ちなみにVMworld Japan 2021でCarographerについて話します。興味のある方はぜひご登録ください。 https://vmworld.jp/content/MA11160/ 2021/11/26 13:40-14:20です。