Rancherのカスタムカタログの作成
Rancherカスタムカタログの作成
前回はDjangoを使ったサーバアプリケーション作成、GitLab Pipelineを使ったサーバアプリケーションのコンテナイメージのビルドとGitLab CRへの保存、そして自動テストについて解説しました。
今回はサーバアプリケーションをRancherのカタログアプリケーションとして公開する方法を解説します。具体的なチャートの構成などについては第3回、RancherのCatalog機能を詳細に見てみるに記載のとおりです。以降はカタログの公開&Rancherでの読み込み方法と、サーバアプリケーションの公開方法について解説します。
用語の整理
少し混乱を招くことが多いので、ここでRancherのCatalog機能にまつわる用語を整理しておきたいと思います。
Rancherのカタログは、デプロイ可能なカタログアプリケーションの集合です(RancherのGUI上では「App」と表現されることが多いようです)。これを図示化すると、Rancherのカタログとカタログアプリケーションの関係は以下の図1のようになります。
以降で説明するRancherカスタムカタログは、標準で提供されているRancherカタログ(正確にはBuilt-in Global Catalog)とは異なり、自身でカスタマイズまたは自作したカタログであることからRancherカスタムカタログ(または単にカスタムカタログ)と呼びます。
カタログの提供方法
自分で作成したカスタムカタログを公開する場合も、Helmのチャートリポジトリを公開する場合と同様にどうやって公開するかという問題が生じます。Rancherのカタログの提供方法としては、Helmと同様に以下の4つが存在します。
- NginxなどのWebサーバへのホスティング
- ChartMuseumなどの専用ソフトウェアを用いたホスティング
- GitHub/GitLab Pagesを使ったホスティング
- S3/GCSなどのマネージドなオブジェクトストレージの静的ページ公開機能を使ったホスティング
今回は、可能な限り特定のサービスやパブリッククラウドなどに依存しない形でカスタムカタログを公開するために、1の方法に則って解説します。
Nginxを使ったRancherカスタムカタログの提供
カスタムカタログをNginxを使って提供する方法について解説していきます。Nginxを使ったカタログの提供ですが、今回は少し手順が複雑になっています。理由としては、Rancherカスタムカタログの配布を行うチャート自体をRancherで管理するには、ブートストラッピングが必要だからです。幸い、Rancherカタログのチャート定義はHelmチャートと互換性があるので、図2に示すように2段階の手順を踏むことでカスタムカタログ自体もRancherのカタログアプリケーションとして管理することが可能になります。
全体の流れを図2から解説すると、以下の5ステップになります。
- HelmチャートとしてRancherカタログのチャートをデプロイ
- Rancherからカスタムカタログとして、1.でデプロイされたアプリケーション(ブートストラップ用のRancherカタログアプリ)をRancherでカスタムカタログとして読み込み
- ブートストラップ用のRancherカタログからRancherカタログアプリをデプロイ
- 3.でデプロイしたアプリを、Rancherでカスタムカタログとして読み込み
- 4.で読み込んだカスタムカタログからサーバアプリケーションをデプロイ
このようにして、カスタムカタログを提供するためのアプリケーション自体もカタログアプリケーションとしてRancherの管理下に含めてしまいましょう。このようにカスタムカタログ自体もRancherで管理することで、カスタムカタログのアップデートもRancherから実施できるようになります。では個々のステップを解説していきましょう。
Rancherカスタムカタログのチャート作成
ここでは、カスタムカタログのカタログアプリケーションの準備を通じて、カスタムカタログのデプロイ方法と、カタログアプリケーションの記述方法について学びます。
さて、それではカタログアプリケーションを作成していきましょう。リポジトリのルートディレクトリ配下にchartディレクトリを作成して、その配下にRancherカスタムカタログのチャート(repository)を作成します(リスト1)。作成の際にはhelmコマンドを活用することで全体の雛形が作成されるので、これを適宜流用しても良いでしょう。Helmのインストール手順については公式のGitHubリポジトリを参照してください。
$ mkdir chart && cd chart $ helm create repository
repository/template以下にkubernetesのリソースマニフェストのテンプレートが作成されているので一旦削除します。helm createコマンドで生成されるテンプレートを流用してもかまいませんが、今回の場合はイチから作ってしまったほうが早いと判断しました。なお、今回作成するRancherカタログのチャート(以降、repositoryチャート)とその関連ファイル構成は、以下のようになります(リスト2)。(一部カタログアプリケーションとしてオプションとなるファイルについては作成していません)
個別ファイルの意味合いは、RancherのCatalog機能を詳細に見てみるを参照してください。
chart/ ├ Dockerfile └ repository/ ├ Chart.yaml ├ Values.yaml ├ questions.yaml ├ charts/ └ templates/ ├ _helpers.tpl ├ repository-ingress.yaml ├ repository-deployments.yaml ├ repository-secret.yaml └ repository-service.yaml
まずはChart.yamlです。特にこれ自体はカタログアプリケーションの機能に影響を与えるものではないため、最小限の記述で済ませておきます(リスト3)。なお、nameとversionだけは、パッケージングした際のファイル名に影響する点に注意してください。
apiVersion: v1 appVersion: "1.0" description: Rancher chart repository name: repository version: 0.1.0
次にtemplatesディレクトリ配下にある一連のファイルです。ここで作成しているカタログアプリケーションのイメージを図3に示します。
アクセスの入り口として、Ingress(ingress-repository)が存在し、その後段にService(service-repository)があります。最後にアクセス先としてDeployment(deployments-repository)が配置されています。これを頭の隅においた上でtemplatesディレクトリ配下のファイルを見ていきます。
最初は、repository-ingress.yaml(リスト4)です。図3の要素のうちの、ingress-repositoryを定義しています。Values.yamlまたはチャートインストール時にspec.rules[0].hostの値を指定するようにしています。これで外部からアクセスする際のFQDNを差し替えることが出来るようにしてあります。※1
※1:Ingressで与えるhostの値(FQDN)を簡単に処理するには、external-dnsをクラスタに導入すると良いでしょう。
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-repository labels: app: repository spec: rules: - host: {{ .Values.repository.host }} http: paths: - path: / backend: serviceName: service-repository servicePort: 80
spec.rules[0].http.paths[0].backend.serviceNameでIngressからアクセスする先のServiceとして、service-repositoryを指定しています。では、service-repositoryを定義しているrepository-service.yamlの中身(リスト5)を見ていきましょう。
apiVersion: v1 kind: Service metadata: name: service-repository labels: app: repository spec: type: ClusterIP ports: - name: http port: 80 protocol: TCP targetPort: 80 selector: app: repository
repository-service.yamlですが、type: ClusterIPを指定している点には注意してください。今回、筆者が利用した環境ではNGINX Ingress Controllerを利用しています。パブリッククラウドで提供されているロードバランササービスをIngressリソースとして利用する場合は、配下のServiceにはtype: NodePortを指定しなければいけない場合もあるので、その点は注意してください。
次にservice-repositoryの配下にぶら下がるDeployments(実際にはPod)の定義です(リスト6)。
apiVersion: apps/v1 kind: Deployment metadata: name: deployment-repository labels: app: repository spec: replicas: 1 selector: matchLabels: app: repository template: metadata: labels: app: repository spec: containers: - image: {{ .Values.repository.image }}:{{ .Values.repository.tag }} name: deployment-repository ports: - name: http containerPort: 80 protocol: TCP imagePullSecrets: - name: secret-repository
今回準備するカスタムカタログは、常時高い可用性や性能を求められるものではないので、replicasには1を指定しています。イメージの変更やアップデートに対応できるよう、外部から値を差し込めるようにコンテナイメージを指定する部分は、image: {{ .Values.repository.image }}:{{ .Values.repository.tag }}としています。
さらに、今回のコードリポジトリはGitLabのプライベートリポジトリとして作成しているため、GitLab Container Registory(以下、GitLab CR)もプライベートレジストリになっています。従って、imagePullSecretsの指定が必要です。今回はsecret-repositoryを指定しており、これはrepository-secret.yamlの中で定義しています。
secret-repositoryではGitLab CRで利用するための認証情報として.dockerconfigjsonを定義しています(リスト7)。さらに個々に後から値を差し込めるように定義していますが、これまで定義していた.Values~とは異なる形になっています。
apiVersion: v1 kind: Secret type: kubernetes.io/dockerconfigjson metadata: name: secret-repository data: .dockerconfigjson: {{ template "imagePullSecret" . }}
.dockerconfigjson: {{ template "imagePullSecret" . }}のtemplate~以下の部分はどういう意味を表しているのでしょうか、それは_helpers.tplを見ると分かります。
{{- define "imagePullSecret" }} {{- printf "{\"auths\":{\"%s\":{\"auth\":\"%s\"}}}" .Values.imageCredentials.registry (printf "%s:%s" .Values.imageCredentials.username .Values.imageCredentials.password | b64enc ) | b64enc }} {{- end }}
リスト8の中にあるように、このファイルの中ではimagePullSecretというキーを定義しています。respository-secret.yaml内の{{ template "imagePullSecret" . }}で最終的に生成されるのは、以下のような形式のメッセージ(リスト9)をbase64エンコードしたものになります。
{ "auths": { ".Values.imageCredentials.registry" : { "auth": "'.Values.imageCredentials.username:.Values.imageCredentials.password'をbase64エンコードしたもの" } } }
_helpers.tplでは、kubernetesのリソースを定義しているテンプレートとは別に、テンプレートのヘルパーを記述しています。具体的には、単純にテンプレートにそのまま記述してしまうとあまりに長すぎる記述になってしまう場合や、同じ定義をあちこちで繰り返し利用する場合に別名をつけることでリソースマニフェストファイル本体の見通しを良くします。今回は、GitLab CRからイメージを取得するための認証情報を、Values.yamlまたは後から差し込まれた値を使って作成できるようにしてあります。
最後にValues.yaml(リスト10)とquestions.yaml(リスト11)を見ていきましょう。
repository: # Helmリポジトリのホスト名(FQDN) host: repository.web.ryoma0923.work # HelmリポジトリのDockerイメージリポジトリ image: registry.gitlab.com/fufuhu/ti_rancher_k8s_sampleapp/todo/repository # HelmリポジトリのDockerイメージタグ tag: latest imageCredentials: # Dockerイメージのレジストリ registry: registry.gitlab.com # レジストリ認証用のユーザ名(今回は任意の文字列) username: registry_user # レジストリ認証用のユーザパスワード(機密情報なのでダミーの値) password: dummy
values.yamlでは、チャートのデフォルト値を設定します。ここで指定した値はRancherのGUIやコマンドラインオプションなど様々な方法で上書きすることができます。
questions: # イメージレジストリおよびその認証情報 - variable: imageCredentials.registry type: string label: "Image Registry domain" group: "Registry Information" description: "Image registry domain" default: registry.gitlab.com - variable: imageCredentials.username type: string label: "Registry user name" group: "Registry Information" description: "Registry user name" default: registry_user - variable: imageCredentials.password type: password label: "Registry user password" group: "Registry Information" description: "Registry user password" # repositoryチャート本体の設定項目 ## 外部公開用のFQDN情報 - variable: repository.host type: string label: "FQDN" group: "Domain information" description: "FQDN" ## チャート本体の情報 ### イメージリポジトリの指定 - variable: repository.image type: string label: "Custom chart repository image" group: "Repository chart information" description: "Repository URI for custom chart repository image" default: registry.gitlab.com/fufuhu/ti_rancher_k8s_sampleapp/todo/repository ### イメージタグの指定 - variable: repository.tag type: string label: "Custom chart repository image tag" group: "Repository chart information" description: "Tag information for custom chart repository image" default: latest
templateディレクトリ配下のリソース内部で{{ .Values.~ }}といった形で定義されているテンプレートの値について、values.yaml上で定義されているデフォルト値を上書きする目的でquestions.yamlを利用します。これはRancherカタログのカタログアプリケーション固有の機能であり、Webブラウザ上でGUIを使った入力を実現することができます。例えば、上記のquestions.yamlがRancherのチャートの構成要素としてWebブラウザ上で表現されると、図4のようになります。
ここまで、いかにもすべてをスムーズに記述してきたように見えますが、実際には途中でhelm templateやhelm lintなどのコマンドで出力や記法に誤りがないかをチェックしつつ、時折helm installを実行して、意図した挙動を実現できているかを確認しながら進めている点には留意してください。
カタログアプリケーションのパッケージング
さて、ここまでの記述が完了したら。カスタムカタログを記述したカタログアプリケーションのパッケージングを行います。カタログアプリケーションは、Helmのチャートと互換性があるため、この作業もhelmコマンドを用いて実行します(リスト12)。
$ cd chart $ helm package repository
パッケージングが終わると、ディレクトリに.tgzファイルが生成されていると思います。これが今回パッケージングされたカタログアプリケーションになります。
カタログのメタデータ(index.yaml)の作成
カスタムカタログがカタログとして動作するには、カタログそのものがどんなカタログアプリケーションを格納しているのかを表すメタデータを持たなければいけません。そのメタデータを提供するのがindex.yamlです。helm repo index チャートの格納されているディレクトリを実行することで、index.yamlを自動生成することができます(リスト13)。
$ helm repo index chart
apiVersion: v1 entries: repository: - apiVersion: v1 appVersion: "1.0" created: 2019-04-03T07:50:52.00229518+09:00 description: Helm chart repository digest: fab582793588171ab089df0a14966f5e3c60c1750365341c30db961d282c9f25 name: repository urls: - repository-0.1.0.tgz version: 0.1.0 generated: 2019-04-03T07:50:52.00178667+09:00
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- GitLabを用いた継続的インテグレーション
- RancherのCatalog機能を詳細に見てみる
- HelmfileでKubernetesマニフェストやKustomization、Helm Chartなどで構成されるアプリケーションを効率的に管理する
- Rancherを構成するソフトウェア
- RancherとCI/CD
- KubernetesのConfig&Storageリソース(その1)
- kustomizeで復数環境のマニフェストファイルを簡単整理
- 「Robusta」でKubernetesクラスタの監視と管理自動化を行う
- CI/CDを使ってみよう
- CI/CD Conference 2023から、Kubernetesの構成をテストする事例を解説したセッションを紹介