Kubernetesとcert-manager、Traefik、Let’s Encryptを使用してサイトをセキュアにする方法
著者は、「Write for Donations」プログラムの一環として、寄付の対象としてDiversity in Tech Fundを選択しました。
はじめに
Kubernetesは、信頼性とスケーラビリティの恩恵を受けるウェブサイトや他のサービスのホスティングにおいて人気のある手段です。個人情報やパスワードなどの機密データとのやり取りが増えるにつれて、ブラウザはすべてのウェブサイトがトラフィックを安全にするためにTLSを使用するよう要求し始めました。しかし、TLSベースのサイトをホストするために必要な動作制御のすべてを管理することは困難です。TLS証明書を取得し、それらの証明書を時間通りに更新し、サーバーを設定してそれらを使用するなどの作業に取り組む必要があります。
幸いなことに、あなたのKubernetesクラスタで複雑さを管理するためのサービスがあります。ネットワークプロキシとしてTraefik Proxy(”トラフィック”と発音します)を使用し、cert-managerを使用して安全な証明書の取得と管理を行うことができます。これらのサービスをLet’s Encryptと組み合わせることで、無料かつ自動化された安全な証明書を提供するプロバイダーを利用することで、証明書の管理負担を軽減することができます。通常は最初のセットアップのみを行えば済むようになります。
このチュートリアルでは、Kubernetesクラスターにcert-manager、Traefik、およびLet’s Encryptをセットアップし、サンプルのウェブサイトサービスと共に、ウェブサイトの安全な証明書を自動的に取得、更新、および使用する方法を説明します。
もし管理されたKubernetesホスティングサービスをお探しであれば、成長を目指したシンプルな管理されたKubernetesサービスをご覧ください。
前提条件
- A Kubernetes cluster accessible with kubectl. If you need to create a cluster, Silicon Cloud has a Kubernetes Quickstart.
- A recent version of kubectl for interacting with your cluster. See the product documentation for installing kubectl on Linux, MacOS, and Windows.
- A Silicon Cloud account with doctl installed and configured. To set this up, see our product documentation for How To Install and Configure doctl.
- Helm version 3 or greater. See the official documentation for installing Helm.
- Experience interacting with a Kubernetes cluster using kubectl. To get started, follow our tutorial, Build and Deploy Your First Image to Your First Cluster.
- A registered domain name. This tutorial will use your_domain. You can purchase a domain name from Namecheap, get one for free with Freenom, or use the domain registrar of your choice.
- DNS set up for your domain name. This tutorial assumes you are using Silicon Cloud DNS, but it is not a requirement. If you are using Silicon Cloud, please see our DNS documentation for details on how to add a domain and How To Point to Silicon Cloud Nameservers From Common Domain Registrars for information on using Silicon Cloud DNS with common domain registrars.
- A Personal Access Token with read and write access for Silicon Cloud DNS, if you are using Silicon Cloud for DNS. Other providers will have similar access tokens.
ステップ1:クラスターでcert-managerのセットアップを行います。
従来、ウェブサイトのセキュア証明書を設定する際には、証明書署名要求を生成し、信頼できる証明書認証機関に証明書を生成してもらう必要がありました。次に、ウェブサーバーをその証明書を使用するように設定し、証明書を最新の状態に保つために毎年同じプロセスを繰り返す必要があります。
しかしながら、2014年にLet’s Encryptが創設されたことで、自動化されたプロセスを通じて無料の証明書を取得することが可能になりました。ただし、これらの証明書は1年ではなく数ヶ月間しか有効ではありませんので、その証明書を自動的に更新するためには、cert-managerというKubernetes上で実行されるサービスを使用する必要があります。このサービスは、証明書のライフサイクルを自動的に管理するために設計されています。
このセクションでは、cert-managerをクラスター内の専用のcert-manager名前空間で実行するために設定します。
最初に、cert-managerのリリースファイルを使用してkubectlでcert-managerをインストールします。
- kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml
デフォルトでは、cert-managerはcert-managerという名前の独自の名前空間にインストールされます。ファイルが適用されると、クラスタ内にいくつかのリソースが作成され、出力に表示されるでしょう(一部の出力は長さのため省略されています)。
namespace/cert-manager created customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created # some output excluded deployment.apps/cert-manager-cainjector created deployment.apps/cert-manager created deployment.apps/cert-manager-webhook created mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
このセクションでは、セキュアな証明書を管理するためにcert-managerをインストールしました。次に、cert-managerに証明書の発行方法を指定する方法を設定する必要があります。次のセクションでは、クラスター内にLet’s Encryptの発行者を設定します。
ステップ2 – Let’s Encrypt証明書発行者の設定を行います。
ウェブサイトにセキュアな証明書を使用することは、ユーザーに対して彼らが表示しているサイトがあなたのサーバーから提供されたものであることを信頼できると伝える方法です。そのためには、証明書発行元は、証明書が対象としているドメインを所有していることを検証する必要があります。Let’s Encryptは、ACMEと呼ばれる標準を使用してこれを行います。ACMEは、ドメインの所有を証明するためにチャレンジを使用します。cert-managerは、さまざまなプロバイダーに対してDNSチャレンジとHTTPチャレンジの両方をサポートしていますが、このチュートリアルでは、Silicon CloudのDNSプロバイダーとDNS-01チャレンジを使用します。
このセクションでは、クラスターにClusterIssuerを作成し、cert-managerにLet’s Encryptから証明書を発行する方法と、Let’s EncryptのDNSチャレンジを完了するために使用する資格情報を指定します。
Note
cert-managerでサポートされている他のプロバイダについての詳細は、cert-managerのドキュメントのACME入門を参照してください。
クラスターのClusterIssuerを作成する前に、クラスター構成のためのディレクトリを作成する必要があります。mkdirコマンドを使用してディレクトリを作成し、そのディレクトリにcdするようにしてください。
- mkdir tutorial-cluster-config
- cd tutorial-cluster-config
ディレクトリを作成したら、このチュートリアルの前提条件の一部として作成したDNSアクセス用のパーソナルアクセストークンが必要になります。Silicon Cloudのアクセストークンは、dop_v1_4321…という長い数字の文字列で似たように表示されます。
アクセストークンをKubernetesのシークレットとして保存するには、それをbase-64エンコードする必要があります。これを行うには、アクセストークンの部分を置き換えて、エコーコマンドを使用してトークンをベース64コマンドにパイプすることができます。
- echo -n ‘dop_v1_4321…‘ | base64
このコマンドは、あなたのアクセストークンをエンコードするためにechoからbase64コマンドへ送信します。-nオプションは、末尾に改行が含まれないようにします。アクセストークンによっては、以下のような出力が表示されます。
ZG9wX3YxX3RoaXNpc25vdGFyZWFsdG9rZW5idXRpbXB1dHRpbmdhYnVuY2hvZnN0dWZmaW5oZXJlc29sZW5ndGhzbWF0Y2g=
次に使うために、この出力はあなたのベース64エンコードされたアクセストークンです。コピーしてください。
ナノまたはお気に入りのエディタを使用して、lets-encrypt-do-dns.yamlという新しいファイルを作成し、開きます。
- nano lets-encrypt-do-dns.yaml
以下のコードを追加して、KubernetesのSecretを作成してください。アクセストークンのaccess-tokenフィールドには、ベース64でエンコードされたアクセストークンを使用してください。
tutorial-cluster-config/lets-encrypt-do-dns.yamlを日本語で言い換えると、以下のようになります:
チュートリアル-クラスター-設定/ Let’s Encrypt-Do-DNS.yaml
apiVersion: v1
kind: Secret
metadata:
namespace: cert-manager
name: lets-encrypt-do-dns
data:
access-token: ZG9wX3Y...
このシークレットはlets-encrypt-do-dnsと呼ばれ、cert-managerの名前空間に保存されます。データセクションには、以前に作成したアクセストークンをBase64でエンコードしたものを含めます。このシークレットは、Let’s Encryptイシュアを作成する際に参照するアクセストークンを安全に保管します。
次に、ファイルを保存して、kubectl applyを使用してクラスターに適用してください。
- kubectl apply -f lets-encrypt-do-dns.yaml
出力には、「クラスター内にシークレットが作成されました」というメッセージが表示されます。
secret/lets-encrypt-do-dns created
さあ、lets-encrypt-issuer.yamlという新しいファイルを作成しましょう。このファイルにはcert-managerのClusterIssuerを含めます。これを使用してLet’s Encryptの証明書を発行します。
- nano lets-encrypt-issuer.yaml
以下の行を追加し、spec.acme.emailフィールドにあなたのメールアドレスを入力してください(これはLet’s Encryptが提供する証明書に関連付けるアドレスです)。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-issuer
spec:
acme:
email: your_email_address
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-issuer-account-key
solvers:
- selector: {}
dns01:
digitalocean:
tokenSecretRef:
name: lets-encrypt-do-dns
key: access-token
最初の2行では、apiVersionとkindがこのKubernetesリソースがcert-managerのClusterIssuerであることを示しています。次に、それをletsencrypt-issuerと名付けます。この場合、namespaceフィールドは含まれていません。なぜなら、このリソースはクラスタリソースであり、単一の名前空間ではなくクラスタ全体に適用されるためです。
次に、スペックセクションで、acmeチャレンジセクションを定義して、cert-managerに対してこのClusterIssuerがletsencrypt-issuerを使用して証明書を発行するよう指示します。メールアドレスは、Let’s Encryptが問題がある場合やcert-managerが適時に更新しない場合に、証明書に関連する通知(更新リマインダーなど)を送信するためのものです。サーバーフィールドでは、ACMEチャレンジのリクエストを送信するためのURLを指定し、プロダクションのLet’s Encrypt URLに設定します。サーバーフィールドの後には、cert-managerがクラスターの生成された秘密鍵を保存するために使用するシークレットの名前を指定するprivateKeySecretRefフィールドを含めます。
spec.acmeセクションで最も重要なセクションの一つは、solversセクションです。このセクションでは、letsencrypt-issuerで使用するために設定するACMEチャレンジソルバーを設定します。このケースでは、dns01ソルバーを1つ含めます。ソルバー構成の最初の部分であるセレクターは、{}に設定されており、「何でも」を意味します。クラスタ内の他の証明書に対して異なるソルバーを使用したい場合は、同じ発行者で追加のセレクターを設定することができます。これについての詳細な手順については、cert-managerのACME Introductionで詳細をご覧いただけます。
dns01セクションの中で、Silicon CloudをDNS-01ソルバーとして使用するため、digitaloceanセクションを追加します。別のクラウドプロバイダーを使用している場合は、ここで他のプロバイダーの設定を行います。このセクションでは、既に作成したSecretのlets-encrypt-do-dnsアクセストークンフィールドを参照するために、tokenSecretRefを含めます。cert-managerは、あなたの代わりにDNSレコードを作成する際に、このアクセストークンを使用します。
発行者ファイルを保存したら、kubectl apply を使用してクラスタに適用してください。
- kubectl apply -f lets-encrypt-issuer.yaml
出力は、letsencrypt-issuerという名前のClusterIssuerが作成されたことを確認します。
clusterissuer.cert-manager.io/letsencrypt-issuer created
このセクションでは、cert-managerを設定し、Let’s Encryptから証明書を発行するように構成しました。しかし、証明書はリクエストされておらず、ウェブサイトを提供するものもなく、クラスター内でウェブサイトサービスが実行されていません。次のセクションでは、Traefikを外部世界とウェブサイトの間のプロキシとして設定します。
ステップ3 – Traefikとロードバランサーの使用
Traefikは、ウェブサイトのトラフィックやクラスタに入出する他のネットワークトラフィックに対応するためにKubernetesと統合するために設計されたオープンソースのプロキシサービスです。ネットワークトラフィックが増えるにつれて、異なるKubernetesノード間でリソース使用量を分散するために、クラスタ内で実行されるTraefikインスタンスの数を増やすことが望ましいかもしれません。このように複数のサービスインスタンスを指すために、ロードバランサを使用してネットワーク接続を受け入れ、異なるTraefikインスタンスに送信することで、ネットワークトラフィックの負荷をバランスさせることができます。
このセクションでは、Traefikをクラスターにインストールし、cert-managerで管理される証明書とステップ5で追加するウェブサイトとの連動を準備します。また、クラスター外からのネットワークトラフィックをTraefikサービスに送信するロードバランサーをセットアップし、複数のTraefikインスタンスを運用する準備もします(お好みで実行する場合)。
最初に、Traefikをインストールするためのtraefikという名前の名前空間を作成してください。これを行うには、traefik-ns.yamlというファイルを開いてください。
- nano traefik-ns.yaml
KubernetesのNamespaceリソースに入力してください。
apiVersion: v1
kind: Namespace
metadata:
name: traefik
ファイルを保存した後、kubectl applyを使用してクラスターに適用してください。
- kubectl apply -f traefik-ns.yaml
一度コマンドが実行されると、クラスタの出力によって名前空間が作成されたことが確認されます。
namespace/traefik created
traefikの名前空間を作成した後、Traefikサービス自体をインストールします。これには、Helmというユーティリティを使用します。Helmは、Kubernetesのためのパッケージマネージャであり、Kubernetesサービスのインストールをコンピュータ上のアプリのように簡単にします。Helmでは、パッケージはチャートと呼ばれます。
最初に、利用可能なリポジトリにtraefik Helmリポジトリを追加する必要があります。これにより、Helmはtraefikパッケージを見つけることができます。
- helm repo add traefik https://helm.traefik.io/traefik
コマンドが完了すると、TraefikリポジトリがコンピュータのHelmリポジトリに追加されたことの確認が届きます。
“traefik” has been added to your repositories
次に、チャートリポジトリを更新してください。
- helm repo update
出力結果によって、Traefikのチャートリポジトリが更新されたことが確認されます。
Hang tight while we grab the latest from your chart repositories… …Successfully got an update from the “traefik” chart repository Update Complete. ⎈Happy Helming!⎈
最後に、作成したクラスター内のtraefik名前空間にtraefikをインストールしてください。
- helm install –namespace=traefik traefik traefik/traefik
このコマンドには多くのtraefikがありますので、それぞれの役割について確認しましょう。最初のtraefikは、–namespace=traefikという指定で、以前作成したtraefikネームスペースにTraefikをインストールするようHelmに伝えます。次に、強調表示されたtraefikは、クラスター内のこのTraefikのインスタンスに付けたい名前です。これにより、同じクラスター内に複数のTraefikインストールがある場合でも、traefik-website1やtraefik-website2などの異なる名前を付けることができます。現在のクラスターにはTraefikのインストールが1つだけですので、単にtraefikという名前を使用できます。3番目のtraefik/は、以前に追加したリポジトリであり、インストール元です。最後に、最後のtraefikは、インストールしたいチャートの名前です。
コマンドを実行すると、以下のような出力が画面に表示されます。
NAME: traefik
LAST DEPLOYED: Sun Oct 2 16:32:57 2022
NAMESPACE: traefik
STATUS: deployed
REVISION: 1
TEST SUITE: None
Helm チャートがインストールされると、Traefik はクラスター上でダウンロードを開始します。Traefik が稼働しているかどうかを確認するには、traefik ネームスペースに作成されたすべての Traefik リソースを表示するために、「kubectl get all」と実行してください。
- kubectl get -n traefik all
以下の出力は、あなたの出力と似たようなものになります。
NAME READY STATUS RESTARTS AGE pod/traefik-858bb8459f-k4ztp 1/1 Running 0 94s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/traefik LoadBalancer 10.245.77.251 <pending> 80:31981/TCP,443:30188/TCP 94s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/traefik 1/1 1 1 94s NAME DESIRED CURRENT READY AGE replicaset.apps/traefik-858bb8459f 1 1 1 94s
クラスタや前回のコマンドの実行時によって、一部の名前や年齢が異なる場合があります。もし、 がサービス/traefikの EXTERNAL-IP の下に表示された場合は、IPアドレスが表示されるまで kubectl get -n traefik all コマンドを実行し続けてください。EXTERNAL-IP は負荷分散装置がインターネットから利用可能な IP アドレスです。一度IPアドレスが表示されれば、traefik_ip_address としてそのIPアドレスをメモしておいてください。次のセクションでドメインの設定に使用します。
このセクションでは、Traefikをクラスターにインストールし、ウェブサイトのトラフィックをリダイレクトするためのEXTERNAL-IPが取得できました。次のセクションでは、ドメインのトラフィックをロードバランサーに送信するためにDNSの変更を行います。
ステップ4 – ドメインでTraefikにアクセスする
クラスターにTraefikが設定され、負荷分散装置を介してインターネットからアクセス可能になったら、ドメインのDNSをTraefikの負荷分散装置を指すように更新する必要があります。続行する前に、ドメインがSilicon Cloudのアカウントに追加されていることを確認してください。cert-managerは、以前に設定したアクセストークンを使用してドメインのDNS設定を更新できる必要があります。doctlを使用して、ドメインのDNSレコードをTraefikの負荷分散装置を指すように設定します。
Note
まず、tutorial-proxy.your_domainというドメインのDNS Aレコードを作成し、それをtraefik_ip_addressに指すようにしてください。
- doctl compute domain records create your_domain –record-name tutorial-proxy –record-type A –record-data traefik_ip_address
DNSのAレコードは、特定のホスト名を特定のIPアドレスに向けるようDNSに指示するものです。この場合、tutorial-proxy.your_domainはtraefik_ip_addressに向けられます。したがって、誰かがtutorial-proxy.your_domainのウェブサイトを要求した場合、DNSサーバーは彼らをtraefik_ip_addressに誘導します。
コマンドを実行した後、レコードが作成されたことを確認するメッセージが表示されます。
ID Type Name Data Priority Port TTL Weight 12345678 A tutorial-proxy traefik_ip_address 0 0 1800 0
指示されたように、tutorial-service.your_domainという名前のCNAMEタイプのDNSレコードを作成し、tutorial-proxy.your_domainに向ける。クラスター内で複数のサービスを実行することが予想されるため、各ドメインをTraefikプロキシにポイントするためにAレコードを使用すると、プロキシのIPアドレスを変更する必要がある場合に多くの作業が必要になります。ただし、CNAMEを使用すると、DNSに対して指定したドメインのアドレスを使用するように指示できます。この場合、ドメインはtutorial-proxy.your_domainなので、複数のAレコードではなく、1つのAレコードを更新して新しいIPアドレスを指定するだけで済みます。
CNAMEレコードを作成するために、再びdoctlコマンドを使用してください。–record-dataには末尾にピリオド(.)を含めるようにしてください。
- doctl compute domain records create your_domain –record-name tutorial-service –record-type CNAME –record-data tutorial-proxy.your_domain.
これにより、tutorial-service.your_domainというCNAME DNSレコードが作成され、tutorial-proxy.your_domainを指すようになります。これにより、tutorial-service.your_domainをリクエストすると、DNSサーバーはtutorial-proxy.your_domainが指しているIPアドレスに接続するように伝えます。–record-data内の最後のドットは、提供されているドメインの終わりであることをDNSサーバーに伝え、他の情報を追加しないようにします。これは、ピリオド(.)が文末を示すためのものと同様です。
コマンドを実行すると、以下のような出力が表示されます。
ID Type Name Data Priority Port TTL Weight 12345679 CNAME tutorial-service tutorial-proxy.your_domain 0 0 1800 0
デジタルオーシャンがあなたの主要なDNSサーバーであるため、他のインターネット上のDNSサーバーの更新を待つのではなく、直接サーバーにクエリを行って正しく設定されているかを確認することができます。DNSサーバーを通じて設定が正しく伝達されているかを確認するために、ns1.digitalocean.comというSilicon Cloudの主要DNSサーバーがどのように記録するかを確認するために、digコマンドを使用してください。
Note
- dig @ns1.digitalocean.com +noall +answer +domain=your_domain tutorial-proxy tutorial-service
digというユーティリティは、DNSサーバーに直接接続してDNSレコードを調べるためのものです。この場合、@ns1.digitalocean.comという情報を提供することで、digにns1.digitalocean.comサーバーのDNSレコードをクエリするよう指示します。 “+noall +answer”のオプションは、digに短い応答のみを出力するよう指示します。 (DNSクエリに関する詳細情報が必要な場合は、これらの2つのオプションを削除することもできます。) Digの詳細については、「Digを使用してDNS情報を取得するガイド」をご覧ください。
次に、+domain=your_domainを使用すると、digに対して提供されたホスト名の末尾に.your_domainを追加するよう指示します。最後に、tutorial-proxyとtutorial-serviceは調べるホスト名です。+domainオプションを使用しているので、tutorial-proxy.your_domainというフレーズ全体を使用する必要はありません。自動的に末尾に追加されます。
以下のような出力が得られるはずです。ただし、”your_domain”と”traefik_ip_address”の値はご自身のものに置き換えてください。
tutorial-proxy.your_domain. 1662 IN A traefik_ip_address tutorial-service.your_domain. 1800 IN CNAME tutorial-proxy.your_domain. tutorial-proxy.your_domain. 1800 IN A traefik_ip_address
以下は、日本語に自然に言い換えたものです。
出力の最初の行は、tutorial-proxy.your_domainがtraefik_ip_addressを指すA(IN A)レコードであることを示しています。2行目は、tutorial-service.your_domainがtutorial-proxy.your_domainを指すCNAME(IN CNAME)レコードであることを確認しています。最後の行は、CNAMEレコードが指すアドレスをdigコマンドが検索するクエリです。tutorial-proxy.your_domainが指すAレコードのIPアドレスが前回と同じであるため、同じものが表示されます。
このセクションでは、AタイプのDNSレコードとCNAMEタイプのDNSレコードをドメインに追加しました。これにより、ブラウザなどのネットワーククライアントが、Traefikサービスに接続するための場所を把握できるようになります。次のセクションでは、構成を完了するために、クラスター内に一時的なウェブサーバーをセットアップします。
ステップ5 – ウェブサービスの作成
前のセクションでは、cert-managerとTraefikの設定を行い、ウェブサイトのセキュアな証明書を処理し、ウェブトラフィックをウェブサービスにルーティングする準備をしました。しかし、現時点ではウェブトラフィックを送るウェブサービスはまだありません。このセクションでは、クラスタ内でホストするウェブサイトをシミュレートするために、Nginxウェブサーバーを使用します。
ウェブサイトをシミュレートするために、nginxのDockerイメージを使用してデプロイメントを設定します。これにより、Nginxの「Welcome!」ページのみが表示されますが、これによってすべてが正しく接続され、期待どおりに機能していることが保証されます。
最初に、tutorial-service.yamlという名前のファイルを作成してください。
- nano tutorial-service.yaml
以下のコードを追加して、tutorialという名前のNamespaceとtutorial-serviceという名前のDeploymentを作成します。
apiVersion: v1
kind: Namespace
metadata:
name: tutorial
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: tutorial
name: tutorial-service
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: tutorial-service
app.kubernetes.io/part-of: tutorial
template:
metadata:
labels:
app.kubernetes.io/name: tutorial-service
app.kubernetes.io/part-of: tutorial
spec:
containers:
- name: service
image: nginx
ports:
- containerPort: 80
前のtraefikネームスペースと同様に、このファイルの最初のリソースは、tutorialという名前の新しいネームスペースをクラスターに作成します。次のリソースであるtutorial-serviceデプロイメントでは、クラスター内でウェブサイトのレプリカを3つ実行したいと指定しています。そのため、1つがクラッシュしても、残りの2つが残り、3番目のレプリカが復帰するまで動作します。
次のセクション、セレクターは、このデプロイメントに関連するポッドをKubernetesがどのように見つけるかを示します。この場合、ラベルが一致するポッドを見つけます。テンプレートセクションでは、各ポッドがどのように見えるかを定義します。メタデータセクションでは、セレクターで一致するラベルを提供し、スペックでは、ポッド内の名前が「service」で、nginxイメージを使用し、ネットワーク接続を80ポートで待ち受けるコンテナが1つ必要であることを指定します。
変更内容を保存したら、クラスターに適用してください。 (Henkō naiyō o hozon shitara, kurasutā ni tekiyō shite kudasai.)
- kubectl apply -f tutorial-service.yaml
出力確認は、チュートリアルの名前空間とチュートリアルサービスの展開が作成されたことを確認します。
namespace/tutorial created deployment.apps/tutorial-service created
デプロイメントが実行中かどうかを確認するには、kubectl get podsコマンドを使用して、チュートリアルの名前空間で実行しているポッドのリストを表示することができます。
- kubectl get -n tutorial pods
以下と似たような出力が表示されます。
NAME READY STATUS RESTARTS AGE tutorial-service-568b4f8477-hpstl 1/1 Running 0 2m15s tutorial-service-568b4f8477-mcpqd 1/1 Running 0 2m15s tutorial-service-568b4f8477-mg8mb 1/1 Running 0 2m15s
「kubectl apply」と「kubectl get」のコマンドを実行した間の経過時間によってAGEが異なる可能性があるが、RunningのSTATUSを持ち、名前がtutorial-service-で始まる3つのポッドのリストを見つけるべきです。
あなたのウェブサービスが稼働しているので、3つのポッド間でトラフィックを送信する方法が必要です。Kubernetesでは、これにはServiceを使用します。Serviceに送信されたトラフィックは、Serviceが指し示す各ポッド間で負荷分散されます。
サービスを作成するために、もう一度tutorial-service.yamlファイルを開き、末尾にサービスを追加してください。
...
- name: service
image: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: tutorial
name: tutorial-service
spec:
selector:
app.kubernetes.io/name: tutorial-service
app.kubernetes.io/part-of: tutorial
ports:
- protocol: TCP
port: 80
targetPort: 80
次のように日本語で言い換えます:
Deploymentと同様に、Serviceにはトラフィックを送信したいポッドを見つけるためのラベルをリストアップするセレクターのセクションがあります。これらのラベルは、Deploymentのポッドテンプレートセクションに含まれているラベルと一致します。Serviceにはまた、ポートセクションに1つのポートがリストアップされており、サービスのポート80に送信されるTCPトラフィックは、ロードバランサーによって選択されたポッドのtargetPort: 80に送信されるようになっています。
変更を保存した後、クラスタにサービスを適用してください。
- kubectl apply -f tutorial-service.yaml
今回の出力では、名前空間とデプロイメントは変更されていません(何の変更も行っていないため)、tutorial-serviceが作成されました。
namespace/tutorial unchanged deployment.apps/tutorial-service unchanged service/tutorial-service created
チュートリアルサービスが作成されたら、kubectl port-forwardコマンドを使用してサービスをローカルコンピュータで利用可能にし、サービスにアクセスできるかどうかをテストできます。
- kubectl port-forward -n tutorial service/tutorial-service 8888:80
このコマンドは、ローカルコンピュータのポート8888に送信されたトラフィックをクラスタ内のtutorial-serviceのポート80に転送します。Kubernetesクラスタでは、tutorial-serviceサービスをポート80での接続待ち状態に設定し、ローカルコンピュータからそのサービスにトラフィックを送る方法が必要です。コマンドでは、service/tutorial-serviceをtutorial名前空間内でポートフォワードすることを指定し、ポートの組み合わせ8888:80を提供します。リストされた最初のポートは、ローカルコンピュータが待機するポートであり、2番目のポート(:の後ろのポート)は、トラフィックが送信されるservice/tutorial-service上のポートです。ローカルコンピュータのポート8888にトラフィックを送信すると、そのトラフィックはすべてservice/tutorial-service上のポート80に送信され、最終的にservice/tutorial-serviceが指し示すポッドに送信されます。
コマンドを実行すると、以下のような出力が表示されます。
Forwarding from 127.0.0.1:8888 -> 80 Forwarding from [::1]:8888 -> 80
コマンドは戻り値を返さず、トラフィックを転送し続けることに注意してください。
「サービスにリクエストを行うために、コンピューター上でセカンドターミナルを開き、ポート8888を使用してcurlコマンドを自分のコンピューターに対して実行してください。」
- curl http://localhost:8888/
このコマンドは、あなたのフォワーディングポート(8888)を介してクラスターのtutorial-serviceにHTTPリクエストを行い、Nginxのウェルカムページが含まれたHTMLレスポンスを返します。
<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href=”http://nginx.org/”>nginx.org</a>.<br/> Commercial support is available at <a href=”http://nginx.com/”>nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
元のターミナルで、ポートフォワードのコマンドを停止するためには、今すぐCONTROL+Cを押すことができます。また、curl接続を行った際に追加の出力も表示されます。
Forwarding from 127.0.0.1:8888 -> 80 Forwarding from [::1]:8888 -> 80 Handling connection for 8888
このセクションでは、DeploymentとServiceを使用してクラスター内にnginxウェブサービスをセットアップします。その後、curlコマンドでkubectl port-forwardを使用して、nginxが正常に動作していることを確認します。cert-manager、Traefik、およびサービスがセットアップされたことを考慮して、次のセクションでこれらを組み合わせ、cert-managerとTraefikを使用してインターネット上でHTTPSでサービスを利用できるようにします。
ステップ6 — ウェブサービスを利用可能にし、セキュリティを確保する
あなたのクラスター内では、すべての個別のサービスが実行されていますが、それらは比較的独立して動作しています。cert-managerはただそこに座っているだけで、Traefikはどのサイトを提供すべきかを知りませんし、Nginxのウェブサイトはクラスターにポート転送しない限り利用できません。このセクションでは、すべてのサービスを接続するためにIngressリソースを作成します。
最初に、再びtutorial-service.yamlを開いてください。
- nano tutorial-service.yaml
前述したチュートリアルサービスの後に、ファイルの最後にIngressを追加してください。自分自身のドメイン名で設定を更新し、— を先頭に追加して、上記のサービスリソースとIngressリソースを区別してください。
...
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tutorial-service-ingress
namespace: tutorial
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
cert-manager.io/cluster-issuer: letsencrypt-issuer
spec:
rules:
- host: tutorial-service.your_domain
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tutorial-service
port:
number: 80
tls:
- secretName: tutorial-service-cert
hosts:
- tutorial-service.your_domain
以下の行には、すべてがどのように組み合わさるかを伝えるためのルールと注釈が含まれています。Ingressリソースには、Traefik、cert-manager、およびあなたのチュートリアルサービスへの参照が含まれています。注釈セクションには、いくつかの異なるが重要な注釈が含まれています。
traefik.ingress.kubernetes.io/router.entrypointsアノテーションは、このIngressのトラフィックがwebsecureエントリーポイントを介して利用可能であることをTraefikに伝えます。これは、Helmチャートがデフォルトで設定するエントリーポイントで、HTTPSトラフィックを処理し、traefik_ip_addressの443ポート、つまりHTTPSのデフォルトポートでリッスンします。
次の注釈、traefik.ingress.kubernetes.io/router.tlsは、TraefikにHTTPSトラフィックのみに応答するように設定されています。ウェブサイトが機密データを処理するために安全である必要があるため、ユーザーが誤って安全でないバージョンを使用しないようにしたいのです。
最後の注釈、cert-manager.io/cluster-issuerはletsencrypt-issuerに設定され、このIngressの安全な証明書発行時にcert-managerに使用してほしい発行者を指定します。現時点ではletsencrypt-issuerが唯一の設定された発行者ですが、後でさらに追加し、異なるサイトに異なる発行者を使用することもできます。
Ingressのspec.rulesセクションには、Ingressに送信されるトラフィックのルーティングに関するルールを1つ含めます。それによれば、tutorial-service.your_domainというホストに対して、指定されたパスに対してhttpを使用するということです。含まれているパスは、パスタイプがPrefixであるルートの/pathのみであり、これは送信されたトラフィックは提供されたバックエンドに送信されるべきことを意味します。バックエンドセクションでは、それがサービスであると説明されており、送信すべきトラフィック先は前に作成したtutorial-serviceサービスであり、トラフィックはサービスのポート80に送信されるべきです。
イングレスのspec.tlsセクションは、cert-managerがセキュア証明書を要求および発行するために必要な情報を提供し、同様にTraefikがこれらの証明書を使用するために必要な情報も提供します。secretNameは、cert-managerが発行したセキュア証明書を配置するKubernetes Secretであり、Traefikが発行された証明書をロードするために使用するSecretです。hostsセクションは、cert-managerが証明書を要求するホスト名のリストです。この場合、tutorial-service.your_domainのホスト名のみを含みますが、複数のホスト名に対応させたい場合は、所有する他のホスト名も追加することができます。
作成したIngressを保存した後、kubectl applyを再度使用して新しいリソースをクラスターに適用してください。
- kubectl apply -f tutorial-service.yaml
イングレスが作成され、他のリソースは変更されません。
namespace/tutorial unchanged deployment.apps/tutorial-service unchanged service/tutorial-service unchanged ingress.networking.k8s.io/tutorial-service-ingress created
Ingressが作成されると、Traefikは自動的に設定を行い、cert-managerは証明書の発行を行うためのチャレンジ/レスポンスプロセスを開始します。数分かかる場合があるため、チュートリアルの名前空間にある証明書を確認することで、証明書が発行されたかどうかを確認できます。
- kubectl get -n tutorial certificates
以下のような出力が受け取れます。
NAME READY SECRET AGE tutorial-service-cert False tutorial-service-cert 12m
もしREADYフィールドがFalseであれば、証明書はまだ発行されていません。同じコマンドを繰り返し実行して、READYフィールドがTrueに変わるまで待つことができます。証明書の発行には時間がかかる場合がありますが、数分以上かかる場合は、設定に問題がある可能性があります。
Note
kubectl logs -n cert-manager deployment/cert-manager –tail=10 -f
「証明書が準備できたら、curlを使用してクラスターに対してHTTPSリクエストを行うことができます。」
- curl https://tutorial-service.your_domain
Note
curl https://tutorial-service.your_domain –resolve ‘tutorial-service.your_domain:443:traefik_ip_address’
このコマンドは、curlコマンドによって、ポート443でのtutorial-service.your_domainのDNS解決をtraefik_ip_addressで上書きするために、–resolveオプションを使用するよう指示しています。 DNSの結果が正しくないため、これにより、DNSが完全に更新されるまでクラスタ内のTraefikに接続することができます。
出力結果では、以前のポートフォワーディングで得られた同じNginxの「ようこそ!」ページが表示されますが、今回はインターネット経由でアクセスできます。
<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href=”http://nginx.org/”>nginx.org</a>.<br/> Commercial support is available at <a href=”http://nginx.com/”>nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
ただし、サイトのHTTPバージョンをリクエストしようとすると、応答は受け取れません。
- curl http://tutorial-service.your_domain
404エラーが表示されます。
404 page not found
Webトラフィックに応答しないようにサイトをIngressで構成したため、Traefikはそのアドレスにサイトを設定せず、404エラーを返します。ユーザーがウェブサイトを表示するはずであることを知っている場合、これは彼らを混乱させる可能性があります。そのため、多くの管理者はサーバーを設定して、HTTPトラフィックを自動的にHTTPSサイトにリダイレクトするようにします。また、TraefikもTraefikを更新してすべてのウェブトラフィックをwebsecureポートにリダイレクトするように指示することができます。
- helm upgrade –namespace=traefik traefik traefik/traefik –set ‘ports.web.redirectTo=websecure’
–set ‘ports.web.redirectTo=websecure’ オプションは、Traefikに自動的にリダイレクトを行うように再設定するよう指示します。
以下のようなメッセージが表示されるはずです。Traefikのインストールが「アップグレード」されました。
Release “traefik” has been upgraded. Happy Helming! NAME: traefik LAST DEPLOYED: Sun Oct 2 19:17:34 2022 NAMESPACE: traefik STATUS: deployed REVISION: 2 TEST SUITE: None
日本語で表現すると、以下のようになります:
もしHTTPの場所にリクエストを送ると、サイトの移動が示される出力を受け取ることがあります。
- curl http://tutorial-service.your_domain
この反応は予想されていました。
Moved Permanently
HTTPSサイトにすべてのトラフィックを送りたい場合、TraefikはHTTPサイトからHTTPSサイトへの自動リダイレクトを行います。ウェブブラウザは自動的にリダイレクトを行いますが、curlはリダイレクトを追跡するために追加のオプションである-Lを必要とします。リダイレクトを追跡するために、curlコマンドを-Lオプションで更新してください。
- curl -L http://tutorial-service.your_domain
出力には、あなたのHTTPSサイトからのNginxウェルカムページが含まれます。
<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href=”http://nginx.org/”>nginx.org</a>.<br/> Commercial support is available at <a href=”http://nginx.com/”>nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
この出力は、リダイレクトが予想通りに動作していることを確認しています。
このセクションでは、Cert-Manager、Traefik、およびNginxのウェブサイトを、KubernetesのIngressリソースを使用して結びつけました。また、Traefikの設定を更新して、HTTPトラフィックをHTTPSのウェブサイトにリダイレクトすることで、ユーザーがウェブサイトを見つけられるようにしました。
結論
このチュートリアルでは、Kubernetesクラスターにいくつかの異なるサービスをインストールして、セキュリティ証明書を使用したウェブサイトの実行を簡単にする方法について学びました。 使用するために、cert-managerサービスをインストールして、Let’s Encryptから発行されたTLS証明書のライフサイクルを管理しました。また、Traefikをインストールして、クラスターの外部でウェブサイトを利用可能にし、Let’s Encryptから発行されたTLS証明書を使用しました。最後に、クラスター内にNginxウェブサイトを作成し、cert-managerとTraefikの設定をテストしました。
あなたのクラスターにcert-managerとTraefikが設定されているので、同じクラスターから複数のウェブサイトを単一のcert-managerとTraefikのインストールで提供するために、異なるIngressリソースを使用してさらにウェブサイトをセットアップすることもできます。
あなたは、Traefik Proxyのドキュメンテーションを読むことで、クラスター内でTraefikが提供できるさまざまな機能について詳しく知ることができます。cert-managerにも、Let’s Encryptのチャレンジタイプ以外や、他のソースとの組み合わせ方についての詳しいドキュメントがあります。
Kubernetesクラスターの設定を続けるためには、Kubernetesに関する他のチュートリアルをご覧ください。