この連載が書籍になりました!『RancherによるKubernetes活用完全ガイド

Rancherのカスタムカタログの作成

2019年5月8日(水)
藤原 涼馬
連載6回目となる今回は、作成したアプリケーションをRancherのカタログアプリケーションとして公開する方法を解説する。

Rancherカスタムカタログの作成

前回はDjangoを使ったサーバアプリケーション作成、GitLab Pipelineを使ったサーバアプリケーションのコンテナイメージのビルドとGitLab CRへの保存、そして自動テストについて解説しました。

今回はサーバアプリケーションをRancherのカタログアプリケーションとして公開する方法を解説します。具体的なチャートの構成などについては第3回、RancherのCatalog機能を詳細に見てみるに記載のとおりです。以降はカタログの公開&Rancherでの読み込み方法と、サーバアプリケーションの公開方法について解説します。

用語の整理

少し混乱を招くことが多いので、ここでRancherのCatalog機能にまつわる用語を整理しておきたいと思います。

Rancherのカタログは、デプロイ可能なカタログアプリケーションの集合です(RancherのGUI上では「App」と表現されることが多いようです)。これを図示化すると、Rancherのカタログとカタログアプリケーションの関係は以下の図1のようになります。

図1:Rancherカタログとカタログアプリケーションの関係

図1:Rancherカタログとカタログアプリケーションの関係

以降で説明するRancherカスタムカタログは、標準で提供されているRancherカタログ(正確にはBuilt-in Global Catalog)とは異なり、自身でカスタマイズまたは自作したカタログであることからRancherカスタムカタログ(または単にカスタムカタログ)と呼びます。

カタログの提供方法

自分で作成したカスタムカタログを公開する場合も、Helmのチャートリポジトリを公開する場合と同様にどうやって公開するかという問題が生じます。Rancherのカタログの提供方法としては、Helmと同様に以下の4つが存在します。

  1. NginxなどのWebサーバへのホスティング
  2. ChartMuseumなどの専用ソフトウェアを用いたホスティング
  3. GitHub/GitLab Pagesを使ったホスティング
  4. S3/GCSなどのマネージドなオブジェクトストレージの静的ページ公開機能を使ったホスティング

今回は、可能な限り特定のサービスやパブリッククラウドなどに依存しない形でカスタムカタログを公開するために、1の方法に則って解説します。

Nginxを使ったRancherカスタムカタログの提供

カスタムカタログをNginxを使って提供する方法について解説していきます。Nginxを使ったカタログの提供ですが、今回は少し手順が複雑になっています。理由としては、Rancherカスタムカタログの配布を行うチャート自体をRancherで管理するには、ブートストラッピングが必要だからです。幸い、Rancherカタログのチャート定義はHelmチャートと互換性があるので、図2に示すように2段階の手順を踏むことでカスタムカタログ自体もRancherのカタログアプリケーションとして管理することが可能になります。

図2:Nginxを使ったRancherカタログのブートストラッピング

図2:Nginxを使ったRancherカタログのブートストラッピング

全体の流れを図2から解説すると、以下の5ステップになります。

  1. HelmチャートとしてRancherカタログのチャートをデプロイ
  2. Rancherからカスタムカタログとして、1.でデプロイされたアプリケーション(ブートストラップ用のRancherカタログアプリ)をRancherでカスタムカタログとして読み込み
  3. ブートストラップ用のRancherカタログからRancherカタログアプリをデプロイ
  4. 3.でデプロイしたアプリを、Rancherでカスタムカタログとして読み込み
  5. 4.で読み込んだカスタムカタログからサーバアプリケーションをデプロイ

このようにして、カスタムカタログを提供するためのアプリケーション自体もカタログアプリケーションとしてRancherの管理下に含めてしまいましょう。このようにカスタムカタログ自体もRancherで管理することで、カスタムカタログのアップデートもRancherから実施できるようになります。では個々のステップを解説していきましょう。

Rancherカスタムカタログのチャート作成

ここでは、カスタムカタログのカタログアプリケーションの準備を通じて、カスタムカタログのデプロイ方法と、カタログアプリケーションの記述方法について学びます。

さて、それではカタログアプリケーションを作成していきましょう。リポジトリのルートディレクトリ配下にchartディレクトリを作成して、その配下にRancherカスタムカタログのチャート(repository)を作成します(リスト1)。作成の際にはhelmコマンドを活用することで全体の雛形が作成されるので、これを適宜流用しても良いでしょう。Helmのインストール手順については公式のGitHubリポジトリを参照してください。

リスト1:Rancherカタログのチャート(repository)の作成

$ mkdir chart && cd chart
$ helm create repository

repository/template以下にkubernetesのリソースマニフェストのテンプレートが作成されているので一旦削除します。helm createコマンドで生成されるテンプレートを流用してもかまいませんが、今回の場合はイチから作ってしまったほうが早いと判断しました。なお、今回作成するRancherカタログのチャート(以降、repositoryチャート)とその関連ファイル構成は、以下のようになります(リスト2)。(一部カタログアプリケーションとしてオプションとなるファイルについては作成していません)

個別ファイルの意味合いは、RancherのCatalog機能を詳細に見てみるを参照してください。

リスト2:repositoryカタログアプリケーションのファイル構成

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)。なお、nameversionだけは、パッケージングした際のファイル名に影響する点に注意してください。

リスト3:chart/repository/Chart.yaml

apiVersion: v1
appVersion: "1.0"
description: Rancher chart repository
name: repository
version: 0.1.0

次にtemplatesディレクトリ配下にある一連のファイルです。ここで作成しているカタログアプリケーションのイメージを図3に示します。

図3:repositoryチャートのイメージ

図3:repositoryチャートのイメージ

アクセスの入り口として、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をクラスタに導入すると良いでしょう。

リスト4:chart/repository/templates/repository-ingress.yaml

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)を見ていきましょう。

リスト5:chart/repository/templates/repository-service.yaml

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)。

リスト6:chart/repository/templates/repository-deployments.yaml

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~とは異なる形になっています。

リスト7:chart/repository/templates/repository-secret.yaml

apiVersion: v1
kind: Secret
type: kubernetes.io/dockerconfigjson
metadata:
  name: secret-repository
data:
    .dockerconfigjson: {{ template "imagePullSecret" . }}

.dockerconfigjson: {{ template "imagePullSecret" . }}template~以下の部分はどういう意味を表しているのでしょうか、それは_helpers.tplを見ると分かります。

リスト8:chart/repository/templates/_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エンコードしたものになります。

リスト9:{{ template "imagePullSecret" . }}で生成されるメッセージ(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)を見ていきましょう。

リスト10:chart/repository/values.yaml

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やコマンドラインオプションなど様々な方法で上書きすることができます。

リスト11:chart/repository/questions.yaml

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のようになります。

図4:questions.yamlのブラウザ上での表現

図4:questions.yamlのブラウザ上での表現

ここまで、いかにもすべてをスムーズに記述してきたように見えますが、実際には途中でhelm templatehelm lintなどのコマンドで出力や記法に誤りがないかをチェックしつつ、時折helm installを実行して、意図した挙動を実現できているかを確認しながら進めている点には留意してください。

カタログアプリケーションのパッケージング

さて、ここまでの記述が完了したら。カスタムカタログを記述したカタログアプリケーションのパッケージングを行います。カタログアプリケーションは、Helmのチャートと互換性があるため、この作業もhelmコマンドを用いて実行します(リスト12)。

リスト12:カタログアプリケーションのパッケージング

$ cd chart
$ helm package repository

パッケージングが終わると、ディレクトリに.tgzファイルが生成されていると思います。これが今回パッケージングされたカタログアプリケーションになります。

カタログのメタデータ(index.yaml)の作成

カスタムカタログがカタログとして動作するには、カタログそのものがどんなカタログアプリケーションを格納しているのかを表すメタデータを持たなければいけません。そのメタデータを提供するのがindex.yamlです。helm repo index チャートの格納されているディレクトリを実行することで、index.yamlを自動生成することができます(リスト13)。

リスト13:index.yamlの作成

$ helm repo index chart

リスト14:chart/index.yaml

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
株式会社リクルートテクノロジーズ

ITエンジニアリング本部プロダクティビティエンジニアリング部
クラウドアーキテクトグループ

Rancher JPコミュニティコアメンバー

ユーザ系SIerにてR&Dを経験したのち、2016年より現職。 業務ではパブリッククラウド、コンテナ関連技術を活用した 先進テクノロジーアーキテクチャの事業装着を担当。 Japan Container Days v18.12や、RancherJPのイベント等登壇等複数。

連載バックナンバー

クラウド技術解説
第11回

Rancherコードリーディング入門(3/3)

2020/2/19
前回に続き、紙面の都合で「RancherによるKubernetes活用完全ガイド」に掲載されなかったパートをご紹介します。
クラウド技術解説
第10回

Rancherコードリーディング入門(2/3)

2019/12/25
前回に続き、紙面の都合で「RancherによるKubernetes活用完全ガイド」に掲載されなかったパートをご紹介します。
クラウド技術解説
第9回

Rancherコードリーディング入門(1/3)

2019/11/5
今回からは、紙面の都合で「RancherによるKubernetes活用完全ガイド」に掲載されなかったパートをご紹介します。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています