CircleCIを使用してDigitalOcean Kubernetesへの展開を自動化する方法

_著者は、https://www.brightfunds.org/funds/tech-education [Tech Education Fund]を選択して、https://do.co/w4do-cta [Write for DOnations]プログラムの一環として寄付を受け取りました。 _

前書き

自動化された展開プロセスを持つことは、スケーラブルで復元力のあるアプリケーションの要件であり、GitOps、またはhttps://www.weave.works/blog/gitops-operations-by-pull-request[GitベースのDevOps]は急速に普及しています。 CircleCIなどのツールをGitHubリポジトリと統合して、コードを自動的にテストおよびデプロイできるようにする、Gitリポジトリを使用してCI / CDを整理する一般的な方法。リポジトリに変更を加えたとき。 この種のCI / CDをKubernetesインフラストラクチャの柔軟性と組み合わせると、需要の変化に応じて簡単に拡張できるアプリケーションを構築できます。

この記事では、CircleCIを使用してサンプルアプリケーションをDigitalOcean Kubernetes(DOKS)クラスターにデプロイします。 このチュートリアルを読んだ後、これらの同じ手法を適用して、Dockerイメージとして構築可能な他のCI / CDツールを展開できます。

前提条件

このチュートリアルに従うには、次のものが必要です。

  • DigitalOceanアカウント。https://www.digitalocean.com/docs/getting-started/sign-up/ [サインアップ]に従って設定できます。 DigitalOceanアカウントの場合]ドキュメント。

  • ワークステーションにインストールされているhttps://www.docker.com/[Docker]、およびDockerイメージの構築、削除、実行方法に関する知識。 https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04のチュートリアルに従って、Ubuntu 18.04にDockerをインストールできます。 Ubuntu 18.04でDockerを使用してください]。

  • Kubernetesの仕組みと、Kubernetesでの展開とサービスの作成方法に関する知識。 Kubernetesの紹介の記事を読むことを強くお勧めします。

  • クラスターを制御するコンピューターにインストールされているhttps://kubernetes.io/docs/tasks/tools/install-kubectl/ [+ kubectl +]コマンドラインインターフェイスツール。

  • サンプルアプリケーションイメージの保存に使用するhttps://hub.docker.com/[Docker Hub]のアカウント。

  • GitHubアカウントとGitの基礎知識。 チュートリアルシリーズhttps://www.digitalocean.com/community/tutorial_series/introduction-to-git-installation-usage-and-branches[Gitの概要:インストール、使用法、ブランチ]およびhttps://この知識を構築するには、www.digitalocean.com / community / tutorials / how-to-create-a-pull-request-on-github [GitHubでプルリクエストを作成する方法]を参照してください。

このチュートリアルでは、Kubernetesバージョン `+ 1.13.5 `および ` kubectl `バージョン ` 1.10.7 +`を使用します。

ステップ1-DigitalOcean Kubernetesクラスターの作成

この最初のステップでは、サンプルアプリケーションをデプロイするDigitalOcean Kubernetes(DOKS)クラスターを作成します。 ローカルマシンから実行される `+ kubectl +`コマンドは、Kubernetesクラスターから直接情報を変更または取得します。

DigitalOceanアカウントでhttps://cloud.digitalocean.com/kubernetes/clusters[Kubernetes page]にアクセスします。

[* Kubernetesクラスターの作成]をクリックするか、ページの右上にある緑色の[作成]ボタンをクリックして、ドロップダウンメニューから[クラスター]を選択します。

image:https://assets.digitalocean.com/articles/cart_64920/Create_DOKS.gif [DigitalOceanでのKubernetesクラスターの作成]

次のページでは、クラスターの詳細を指定します。 オン* Kubernetesバージョンを選択*バージョン* 1.13.5-do.0 *を選択。 これが利用できない場合、より高いものを選択してください。

[データセンター地域を選択]で、最も近い地域を選択します。 このチュートリアルでは、* San Francisco-2 *を使用します。

その後、ノードプール*を構築するオプションがあります。 Kubernetesでは、ノードは、ポッドの実行に必要なサービスを含むワーカーマシンです。 DigitalOceanでは、各ノードはドロップレットです。 ノードプールは、単一の*標準ノード*で構成されます。 * 2GB / 1vCPU *構成を選択し、ノード数で 1 Node *に変更します。

必要に応じて、追加のタグを追加できます。これは、DigitalOcean APIを使用する場合、またはノードプールをより適切に整理する場合に便利です。

*名前を選択*で、このチュートリアルでは、 `+ kubernetes-deployment-tutorial`を使用します。 これにより、次のセクションを読んでいる間ずっと簡単にフォローできます。 最後に、緑色の[クラスターの作成]ボタンをクリックしてクラスターを作成します。

クラスターの作成後、UIに* Download Config File *という構成ファイルをダウンロードするボタンが表示されます。 これは、クラスターに対して実行する `+ kubectl `コマンドの認証に使用するファイルです。 ` kubectl +`マシンにダウンロードします。

そのファイルを使用するデフォルトの方法は、 `+ kubectl `で実行するすべてのコマンドで常に `-kubeconfig `フラグとそのパスを渡すことです。 たとえば、設定ファイルを ` Desktop `にダウンロードした場合、次のように ` kubectl get pods +`コマンドを実行します。

kubectl --kubeconfig ~/Desktop/kubernetes-deployment-tutorial-kubeconfig.yaml get pods

これにより、次の出力が生成されます。

OutputNo resources found.

これは、クラスターにアクセスしたことを意味します。 クラスタにポッドがないため、「+ No resources found。+」メッセージは正しいです。

他のKubernetesクラスターを維持していない場合は、kubeconfigファイルをホームディレクトリの「+ .kube +」と呼ばれるフォルダーにコピーできます。 存在しない場合にそのディレクトリを作成します。

mkdir -p ~/.kube

次に、設定ファイルを新しく作成した `+ .kube `ディレクトリにコピーし、名前を ` config +`に変更します。

cp  ~/.kube/config

これで、設定ファイルのパスは「〜/ .kube / config +」になります。 これは、コマンドを実行するときにデフォルトで ` kubectl `が読み取るファイルなので、 `-kubeconfig +`を渡す必要はありません。 以下を実行してください。

kubectl get pods

次の出力が表示されます。

OutputNo resources found.

次に、次を使用してクラスターにアクセスします。

kubectl get nodes

クラスター上のノードのリストを受け取ります。 出力は次のようになります。

OutputNAME                                    STATUS    ROLES     AGE       VERSION
kubernetes-deployment-tutorial-1-7pto   Ready     <none>    1h        v1.13.5

このチュートリアルでは、すべての `+ kubectl `コマンドと_manifest files_に ` default `名前空間を使用します。これらのファイルは、Kubernetesの作業の作業負荷と操作パラメーターを定義するファイルです。 _Namespaces_は、単一の物理クラスター内の仮想クラスターのようなものです。 必要な他のネームスペースに変更できます。常に `-namespace `フラグを使用して ` kubectl +`に渡したり、Kubernetesマニフェストメタデータフィールドで指定したりするようにしてください。 チームの展開と実行環境を整理するのに最適な方法です。 https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ [ネームスペースに関するKubernetesの公式概要]でそれらの詳細を参照してください。

このステップを完了することで、クラスターに対して `+ kubectl +`を実行できるようになりました。 次の手順では、サンプルアプリケーションを格納するために使用するローカルGitリポジトリを作成します。

ステップ2-ローカルGitリポジトリの作成

次に、ローカルGitリポジトリでサンプル展開を構造化します。 また、クラスターで行うすべての展開に対してグローバルなKubernetesマニフェストを作成します。

最初に、後でGitHubにプッシュする新しいGitリポジトリをローカルで作成します。 ホームディレクトリに「+ do-sample-app」という空のフォルダーを作成し、その中に「+ cd」を追加します。

mkdir ~/do-sample-app
cd ~/do-sample-app

次のコマンドを使用して、このフォルダーに新しいGitリポジトリーを作成します。

git init .

このリポジトリ内で、 `+ kube +`という空のフォルダーを作成します。

mkdir ~/do-sample-app/kube/

これは、クラスターにデプロイするサンプルアプリケーションに関連するKubernetesリソースマニフェストを保存する場所になります。

ここで、 `+ kube-general +`という別のフォルダーを作成しますが、今回は作成したGitリポジトリの外部にあります。 ホームディレクトリ内に作成します。

mkdir ~/kube-general/

このフォルダーは、クラスター上の単一のデプロイメントに固有ではなく、複数のデプロイメントに共通のマニフェストを格納するために使用されるため、Gitリポジトリの外部にあります。 これにより、これらの一般的なマニフェストをさまざまな展開に再利用できます。

フォルダーを作成し、サンプルアプリケーションのGitリポジトリを配置したら、DOKSクラスターの認証と承認を調整します。

ステップ3-サービスアカウントの作成

通常、デフォルトの* admin *ユーザーを使用して、他のhttps://kubernetes.io/docs/concepts/services-networking/service/[Services]からKubernetesクラスターへの認証を行うことはお勧めしません。 外部プロバイダーのキーが危険にさらされると、クラスター全体が危険にさらされます。

代わりに、特定の役割を持つ単一のhttps://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/ [サービスアカウント]を使用します。これはすべてhttps:/の一部です。 /kubernetes.io/docs/reference/access-authn-authz/rbac/[RBAC Kubernetes認証モデル]。

この承認モデルは、_Roles_および_Resources_に基づいています。 基本的にはクラスターのユーザーである_Service Account_を作成してから、クラスターでアクセスするリソースを指定するロールを作成します。 最後に、_Role Binding_を作成します。これは、ロールと以前に作成したサービスアカウントを接続し、ロールがアクセスできるすべてのリソースへのアクセスをサービスアカウントに許可します。

最初に作成するKubernetesリソースは、CI / CDユーザーのサービスアカウントで、このチュートリアルでは「+ cicd +」と名付けます。

`〜/ kube-general +`フォルダー内にファイル ` cicd-service-account.yml +`を作成し、お好みのテキストエディターで開きます。

nano ~/kube-general/cicd-service-account.yml

その上に次の内容を書きます:

〜/ kube-general / cicd-service-account.yml

apiVersion: v1
kind: ServiceAccount
metadata:
 name: cicd
 namespace: default

これはYAMLファイルです。すべてのKubernetesリソースは1つを使用して表されます。 この場合、このリソースはKubernetes APIバージョン + v1 +(内部では `+ kubectl `はKubernetes HTTP APIを呼び出してリソースを作成)からのものであり、 ` ServiceAccount +`であると言っています。

`+ metadata `フィールドは、このリソースに関する情報を追加するために使用されます。 この場合、この「 ServiceAccount 」に「 cicd 」という名前を付け、「 default +」名前空間に作成します。

次のように、 `+ kubectl apply +`を実行して、クラスターにこのサービスアカウントを作成できます。

kubectl apply -f ~/kube-general/

次のような出力を受け取ります。

Outputserviceaccount/cicd created

サービスアカウントが機能していることを確認するには、それを使用してクラスターにログインしてみてください。 そのためには、まずそれぞれのアクセストークンを取得して、環境変数に保存する必要があります。 すべてのサービスアカウントには、Kubernetesがhttps://kubernetes.io/docs/concepts/configuration/secret/[Secret]として保存するアクセストークンがあります。

次のコマンドを使用して、このシークレットを取得できます。

TOKEN=$(kubectl get secret $(kubectl get secret | grep cicd-token | awk '{print $1}') -o jsonpath='{.data.token}' | base64 --decode)

このコマンドの動作に関する説明:

$(kubectl get secret | grep cicd-token | awk '{print $1}')

これは、 `+ cicd `サービスアカウントに関連するシークレットの名前を取得するために使用されます。 ` kubectl get secret `はデフォルトのネームスペースのシークレットのリストを返し、 ` grep `を使用して ` cicd `サービスアカウントに関連する行を検索します。 それは、名前が ` grep +`から返される単一行の最初のものであるため、名前を返します。

kubectl get secret  -o jsonpath='{.data.token}' | base64 --decode

これにより、サービスアカウントトークンのシークレットのみが取得されます。 次に、 `+ jsonpath `を使用してトークンフィールドにアクセスし、結果を ` base64 --decode +`に渡します。 トークンはBase64文字列として保存されるため、これが必要です。 トークン自体はhttps://jwt.io/[JSON Web Token]です。

`+ cicd `サービスアカウントを使用してポッドの取得を試みることができます。 次のコマンドを実行し、「+」を「〜kube / config +」の「 server:+」の後にあるサーバーURLに置き換えます。 このコマンドは、このチュートリアルの後半で学習する特定のエラーを提供します。

kubectl --insecure-skip-tls-verify --kubeconfig="/dev/null" --server= --token=$TOKEN get pods

`-insecure-skip-tls-verify +`は、サーバーの証明書を検証する手順をスキップします。これは、テストだけであり、これを検証する必要がないためです。 `-kubeconfig =" / dev / null "`は、 ` kubectl +`が設定ファイルと認証情報を読み取らず、代わりに提供されたトークンを使用することを確認することです。

出力は次のようになります。

OutputError from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:cicd" cannot list resource "pods" in API group "" in the namespace "default"

これはエラーですが、トークンが機能したことを示しています。 受け取ったエラーは、サービスアカウントがリソース「+ secrets +」をリストするために必要な許可を持っていないことに関するものですが、サーバー自体にアクセスできました。 トークンが機能しなかった場合、エラーは次のようになります。

Outputerror: You must be logged in to the server (Unauthorized)

認証が成功したので、次のステップはサービスアカウントの認証エラーを修正することです。 これを行うには、必要な権限を持つロールを作成し、それをサービスアカウントにバインドします。

ステップ4-ロールとロールバインディングの作成

Kubernetesにはロールを定義する2つの方法があります: `+ Role `または ` ClusterRole +`リソースを使用します。 前者と後者の違いは、最初の名前空間は単一の名前空間に適用され、もう一方はクラスター全体に有効であるということです。

このチュートリアルでは単一の名前空間を使用しているため、 `+ Role +`を使用します。

ファイル `+〜/ kube-general / cicd-role.yml +`を作成し、お気に入りのテキストエディターで開きます。

nano ~/kube-general/cicd-role.yml

基本的な考え方は、 `+ default `名前空間のほとんどのKubernetesリソースに関連するすべてのことを行うためのアクセスを許可することです。 あなたの ` Role +`は次のようになります。

〜/ kube-general / cicd-role.yml

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: cicd
 namespace: default
rules:
 - apiGroups: ["", "apps", "batch", "extensions"]
   resources: ["deployments", "services", "replicasets", "pods", "jobs", "cronjobs"]
   verbs: ["*"]

このYAMLは以前に作成したものといくつかの類似点がありますが、ここではこのリソースは「+ Role 」であり、Kubernetes APIの「 rbac.authorization.k8s.io / v1 」からのものです。 ロールに「 cicd 」という名前を付け、「 ServiceAccount 」を作成したのと同じネームスペース(「 default +」)で作成します。

次に、このロールがアクセスできるリソースのリストである「+ rules +」フィールドがあります。 Kubernetesでは、リソースは所属するAPIグループ、リソースの種類、およびそのときに実行できるアクションに基づいて定義され、動詞で表されます。 https://kubernetes.io/docs/reference/access-authn-authz/authorization/#determine-the-request-verb [これらの動詞はHTTPの動詞に似ています]。

私たちの場合、あなたの + Role +`は、次のリソースで、すべての `+ * +`を許可されていると言っています: `+ deployments、` + services`、 + replicasets、` + pods + + jobs + 、および + cronjobs + 。 これは、次のAPIグループに属するリソースにも適用されます: `+" "+(空の文字列)、 + apps ++ batch +、および + extensions +。 空の文字列は、ルートAPIグループを意味します。 リソースの作成時に `+ apiVersion:v1 +`を使用する場合、このリソースはこのAPIグループの一部であることを意味します。

+ Role +`自体は何もしません。また、https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding [+ RoleBinding `]を作成する必要があります。これにより、 ` Role `が何かにバインドされます。ケース、 ` ServiceAccount +`。

ファイル `+〜/ kube-general / cicd-role-binding.yml +`を作成して開きます:

nano ~/kube-general/cicd-role-binding.yml

ファイルに次の行を追加します。

〜/ kube-general / cicd-role-binding.yml

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: cicd
 namespace: default
subjects:
 - kind: ServiceAccount
   name: cicd
   namespace: default
roleRef:
 kind: Role
 name: cicd
 apiGroup: rbac.authorization.k8s.io

`+ RoleBinding `には、このチュートリアルではまだ説明されていない特定のフィールドがあります。 ` roleRef `は、何かにバインドする ` Role `です。この場合、以前に作成した「 cicd 」ロールです。 ` subjects `は、ロールをバインドするリソースのリストです。この場合、「 cicd 」と呼ばれる単一の「 ServiceAccount +」です。

これらのファイルを作成すると、 `+ kubectl apply +`を再び使用できるようになります。 次のコマンドを実行して、Kubernetesクラスターにこれらの新しいリソースを作成します。

kubectl apply -f ~/kube-general/

次のような出力が表示されます。

Outputrolebinding.rbac.authorization.k8s.io/cicd created
role.rbac.authorization.k8s.io/cicd created
serviceaccount/cicd created

さて、前に実行したコマンドを試してください:

kubectl --insecure-skip-tls-verify --kubeconfig="/dev/null" --server= --token=$TOKEN get pods

ポッドがないため、次の出力が生成されます。

OutputNo resources found.

この手順では、CircleCIで使用するサービスアカウントに、リソースの一覧表示、作成、更新などのクラスターで意味のあるアクションを実行するために必要な承認を与えました。 次に、サンプルアプリケーションを作成します。

ステップ5-サンプルアプリケーションの作成

作成するKubernetesの「+ Deployment 」は、https://hub.docker.com/_/nginx [Nginx]イメージをベースとして使用し、アプリケーションは単純な静的HTMLページになります。 Nginxから単純なHTMLを直接提供することで、展開が機能するかどうかをテストできるため、これは素晴らしいスタートです。 後で見るように、ローカルの ` address:port +`に到達するすべてのトラフィックをクラスターのデプロイメントにリダイレクトして、機能しているかどうかをテストできます。

前に設定したリポジトリ内で、新しい `+ Dockerfile +`ファイルを作成し、選択したテキストエディターで開きます。

nano ~/do-sample-app/Dockerfile

次のように書いてください。

〜/ do-sample-app / Dockerfile

FROM nginx:1.14

COPY index.html /usr/share/nginx/html/index.html

これは、Dockerに `+ nginx +`イメージからアプリケーションコンテナを構築するように指示します。

次に、新しい `+ index.html`ファイルを作成して開きます。

nano ~/do-sample-app/index.html

次のHTMLコンテンツを作成します。

〜/ do-sample-app / index.html

<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
 Kubernetes Sample Application
</body>

このHTMLは、アプリケーションが動作しているかどうかを知らせる簡単なメッセージを表示します。

イメージをビルドして実行することにより、イメージが正しいかどうかをテストできます。

まず、次のコマンドを使用してイメージをビルドし、「++」を独自のDocker Hubユーザー名に置き換えます。 ここでユーザー名を指定して、後でDocker Hubにプッシュしたときに機能するようにする必要があります。

docker build ~/do-sample-app/ -t /do-kubernetes-sample-app

次に、イメージを実行します。 次のコマンドを使用します。これにより、イメージが開始され、ポート `+ 8080 `のローカルトラフィックがイメージ内のポート ` 80 +`に転送されます。ポートNginxはデフォルトでリッスンします:

docker run --rm -it -p 8080:80 /do-kubernetes-sample-app

コマンドの実行中、コマンドプロンプトは対話型でなくなります。 代わりに、Nginxアクセスログが表示されます。 ブラウザで `+ localhost:8080 `を開くと、 `〜/ do-sample-app / index.html `のコンテンツを含むHTMLページが表示されます。 ブラウザを使用できない場合は、新しいターミナルウィンドウを開き、次の「 curl +」コマンドを使用してWebページからHTMLを取得できます。

curl localhost:8080

次の出力が表示されます。

Output<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
 Kubernetes Sample Application
</body>

コンテナを停止し(実行中のターミナルで + CTRL + + + C +)、このイメージをDocker Hubアカウントに送信します。 これを行うには、まずDocker Hubにログインします。

docker login

Docker Hubアカウントに関する必要な情報を入力し、次のコマンドで画像をプッシュします( `++`を自分のものに置き換えることを忘れないでください)。

docker push /do-kubernetes-sample-app

サンプルアプリケーションイメージをDocker Hubアカウントにプッシュしました。 次の手順では、このイメージからDOKSクラスターに展開を作成します。

ステップ6-Kubernetesの展開とサービスを作成する

Dockerイメージが作成されて機能するようになったので、クラスターでhttps://kubernetes.io/docs/concepts/workloads/controllers/deployment/[Deployment]を作成する方法をKubernetesに伝えるマニフェストを作成します。

YAMLデプロイメントファイル `+〜/ do-sample-app / kube / do-sample-deployment.yml +`を作成し、テキストエディターで開きます。

nano ~/do-sample-app/kube/do-sample-deployment.yml

ファイルに次のコンテンツを書き込み、「++」をDocker Hubのユーザー名に置き換えてください。

〜/ do-sample-app / kube / do-sample-deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
 name: do-kubernetes-sample-app
 namespace: default
 labels:
   app: do-kubernetes-sample-app
spec:
 replicas: 1
 selector:
   matchLabels:
     app: do-kubernetes-sample-app
 template:
   metadata:
     labels:
       app: do-kubernetes-sample-app
   spec:
     containers:
       - name: do-kubernetes-sample-app
         image: /do-kubernetes-sample-app:latest
         ports:
           - containerPort: 80
             name: http

KubernetesのデプロイはAPIグループ `+ apps `からのものであるため、マニフェストの ` apiVersion `は ` apps / v1 `に設定されます。 「 metadata +」で、「 metadata.labels」という、これまで使用したことのない新しいフィールドを追加しました。 これは、展開を整理するのに役立ちます。 フィールド「+ spec 」は、デプロイメントの動作仕様を表します。 展開は、1つまたは複数のポッドの管理を担当します。この場合、 ` spec.replicas +`フィールドによって単一のレプリカが作成されます。 つまり、単一のポッドを作成および管理します。

ポッドを管理するには、展開が担当するポッドを知っている必要があります。 `+ spec.selector `フィールドはその情報を提供するフィールドです。 この場合、デプロイメントはタグ ` app = do-kubernetes-sample-app `を持つすべてのポッドを担当します。 ` spec.template `フィールドには、このデプロイメントが作成する ` Pod `の詳細が含まれます。 テンプレート内には、 ` spec.template.metadata`フィールドもあります。 このフィールド内の `+ labels `は、 ` spec.selector `で使用されるものと一致する必要があります。 ` spec.template.spec `はポッド自体の仕様です。 この場合、 ` do-kubernetes-sample-app`と呼ばれる単一のコンテナが含まれます。 そのコンテナーのイメージは、以前にビルドしてDocker Hubにプッシュしたイメージです。

このYAMLファイルは、このコンテナがポート「80」を公開し、このポートに「+ http +」という名前を付けることをKubernetesに伝えます。

`+ Deployment `によって公開されているポートにアクセスするには、サービスを作成します。 `〜/ do-sample-app / kube / do-sample-service.yml +`という名前のファイルを作成し、お気に入りのエディターで開きます。

nano ~/do-sample-app/kube/do-sample-service.yml

次に、ファイルに次の行を追加します。

〜/ do-sample-app / kube / do-sample-service.yml

apiVersion: v1
kind: Service
metadata:
 name: do-kubernetes-sample-app
 namespace: default
 labels:
   app: do-kubernetes-sample-app
spec:
 type: ClusterIP
 ports:
   - port: 80
     targetPort: http
     name: http
 selector:
   app: do-kubernetes-sample-app

このファイルは、デプロイメントで使用されるのと同じラベルに「+ Service +」を与えます。 これは必須ではありませんが、Kubernetesでアプリケーションを整理するのに役立ちます。

サービスリソースには、「+ spec 」フィールドもあります。 ` spec.type `フィールドは、サービスの動作を担当します。 この場合、それは「 ClusterIP 」です。つまり、サービスはクラスター内部IPで公開され、クラスター内からのみ到達可能です。 これはサービスのデフォルトの ` spec.type `です。 ` spec.selector `は、このサービスによって公開されるポッドを選択するときに使用されるラベルセレクターの基準です。 ポッドにはタグ「 app:to-kubernetes-sample-app」があるため、ここで使用しました。 「+ spec.ports 」は、このサービスから公開するポッドのコンテナによって公開されるポートです。 ポッドには、「 http 」という名前のポート「+80」を公開する単一のコンテナがあるため、ここでは「+ targetPort 」として使用しています。 サービスは同じ名前でポート ` 80 +`のポートも公開しますが、コンテナのポート/名前の組み合わせとは異なるポート/名前の組み合わせを使用することもできます。

+ Service`および + Deployment`マニフェストファイルを作成したら、 `+ kubectl`を使用してKubernetesクラスターにこれらのリソースを作成できます。

kubectl apply -f ~/do-sample-app/kube/

次の出力が表示されます。

Outputdeployment.apps/do-kubernetes-sample-app created
service/do-kubernetes-sample-app created

これが機能しているかどうかをテストするには、マシン上の1つのポートをKubernetesクラスター内でサービスが公開しているポートに転送します。 `+ kubectl port-forward +`を使用してそれを行うことができます:

kubectl port-forward $(kubectl get pod --selector="app=do-kubernetes-sample-app" --output jsonpath='{.items[0].metadata.name}') 8080:80

サブシェルコマンド `+ $(kubectl get pod --selector =" app = do-kubernetes-sample-app "--output jsonpath = '{。items [0] .metadata.name}')`は、使用したタグに一致するポッド。 それ以外の場合は、 ` kubectl get pods +`を使用してポッドのリストから取得できます。

`+ port-forward +`を実行すると、シェルは対話型でなくなり、代わりにクラスターにリダイレクトされたリクエストを出力します。

OutputForwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

任意のブラウザで「+ localhost:8080+」を開くと、コンテナをローカルで実行したときと同じページが表示されますが、現在はKubernetesクラスタからのものです! 前と同じように、新しいターミナルウィンドウで「+ curl +」を使用して、機能しているかどうかを確認することもできます。

curl localhost:8080

次の出力が表示されます。

Output<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
 Kubernetes Sample Application
</body>

次に、作成したすべてのファイルをGitHubリポジトリにプッシュします。 これを行うには、まずhttps://help.github.com/en/articles/creating-a-new-repository[GitHubにリポジトリを作成]で「+ digital-ocean-kubernetes-deploy +」と呼ばれる必要があります。

このリポジトリをデモンストレーション用にシンプルに保つために、GitHub UIで要求されたときに、新しいリポジトリを + README ++ license +、または `+ .gitignore +`ファイルで初期化しないでください。 これらのファイルは後で追加できます。

リポジトリを作成したら、ローカルリポジトリをGitHubのリポジトリにポイントします。 これを行うには、 + CTRL + + `+ C `を押して ` kubectl port-forward `を停止し、コマンドラインを取得し、次のコマンドを実行して ` origin +`という新しいリモートを追加します。

cd ~/do-sample-app/
git remote add origin https://github.com//digital-ocean-kubernetes-deploy.git

上記のコマンドからの出力はありません。

次に、これまでに作成したすべてのファイルをGitHubリポジトリにコミットします。 まず、ファイルを追加します。

git add --all

次に、コミットメッセージを引用符で囲んで、リポジトリにファイルをコミットします。

git commit -m "initial commit"

これにより、次のような出力が生成されます。

Output[master (root-commit) db321ad] initial commit
4 files changed, 47 insertions(+)
create mode 100644 Dockerfile
create mode 100644 index.html
create mode 100644 kube/do-sample-deployment.yml
create mode 100644 kube/do-sample-service.yml

最後に、ファイルをGitHubにプッシュします。

git push -u origin master

ユーザー名とパスワードの入力を求められます。 これを入力すると、次のような出力が表示されます。

OutputCounting objects: 7, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 907 bytes | 0 bytes/s, done.
Total 7 (delta 0), reused 0 (delta 0)
To github.com:/digital-ocean-kubernetes-deploy.git
* [new branch]      master -> master
Branch master set up to track remote branch master from origin.

GitHubリポジトリページに移動すると、そこにすべてのファイルが表示されます。 GitHubでプロジェクトをセットアップしたら、CI / CDツールとしてCircleCIをセットアップできるようになりました。

ステップ7-CircleCIの構成

このチュートリアルでは、CircleCIを使用してコードが更新されるたびにアプリケーションの展開を自動化するため、GitHubアカウントを使用してCircleCIにログインし、リポジトリを設定する必要があります。

最初に、彼らのホームページhttps://circleci.com [+ https:// circleci.com +]に移動し、*サインアップ*を押します。

画像:https://assets.digitalocean.com/articles/cart_64920/CircleCI_Main_Site.png [circleci-home-page]

GitHubを使用しているため、緑色の[GitHubでサインアップ]ボタンをクリックします。

CircleCIはGitHubの認証ページにリダイレクトします。 CircleCIには、プロジェクトの構築を開始するために、アカウントに対するいくつかの権限が必要です。 これにより、CircleCIはメールを取得し、リポジトリにフックを作成するためのキーと権限を展開し、アカウントにSSHキーを追加できます。 CircleCIがデータをどのように処理するかについての詳細が必要な場合は、https://circleci.com/docs/2.0/gh-bb-integration [GitHub統合に関するドキュメント]を確認してください。

画像:https://assets.digitalocean.com/articles/cart_64920/CircleCI_GitHub_Sign_In.png [circleci-github-authorization]

CircleCIを承認すると、ダッシュボードにリダイレクトされます。

画像:https://assets.digitalocean.com/articles/cart_64920/CircleCI_Welcome_Page.png [circleci-project-dashboard]

次に、CircleCIでGitHubリポジトリを設定します。 CircleCIダッシュボードから*新しいプロジェクトの設定*をクリックするか、ショートカットとして、強調表示されたテキストをGitHubユーザー名で変更して次のリンクを開きます: `+ https://circleci.com/setup-project/gh//digital -ocean-kubernetes-deploy + `。

その後、* Build *を押します。 まだリポジトリに設定ファイルを作成しないでください。最初のビルドが失敗しても心配する必要はありません。

画像:https://assets.digitalocean.com/articles/cart_64840/Set_Up.png [circleci-start-building]

次に、CircleCI設定でいくつかの環境変数を指定します。 プロジェクトの設定を見つけるには、ページの右上にある歯車アイコンの付いた小さなボタンをクリックしてから*環境変数*を選択するか、次のURLを使用して環境変数ページに直接移動します(覚えておいてください)ユーザー名を入力します): + https:// circleci.com / gh // digital-ocean-kubernetes-deploy / edit#env-vars +。 * Add Variable *を押して、新しい環境変数を作成します。

最初に、 `+ DOCKERHUB_USERNAME `および ` DOCKERHUB_PASS +`と呼ばれる2つの環境変数を追加します。これらは、後でイメージをDocker Hubにプッシュするために必要です。 値をそれぞれDocker Hubのユーザー名とパスワードに設定します。

次に、さらに3つを追加します: + KUBERNETES_TOKEN ++ KUBERNETES_SERVER +、および + KUBERNETES_CLUSTER_CERTIFICATE +

`+ KUBERNETES_TOKEN +`の値は、サービスアカウントユーザーを使用してKubernetesクラスターで認証するために以前に使用したローカル環境変数の値になります。 端末を閉じている場合は、いつでも次のコマンドを実行して端末を取得できます。

kubectl get secret $(kubectl get secret | grep cicd-token | awk '{print $1}') -o jsonpath='{.data.token}' | base64 --decode

`+ KUBERNETES_SERVER `は、 ` cicd `サービスアカウントでログインしたときに、 `-server `フラグとして ` kubectl `に渡した文字列になります。 これは、 `〜/ .kube / config `ファイルの ` server:`の後、または初期作成時にDigitalOceanダッシュボードからダウンロードしたファイル ` kubernetes-deployment-tutorial-kubeconfig.yaml +`で見つけることができます。 Kubernetesクラスターのセットアップ。

`+ KUBERNETES CLUSTER CERTIFICATE `も `〜/ .kube / config`ファイルで利用できるはずです。 これは、クラスターに関連する「+ cluster」アイテムの「+ certificate-authority-data」フィールドです。 長い文字列にする必要があります。必ずすべてコピーしてください。

ほとんどの環境変数には機密情報が含まれているため、これらの環境変数をここで定義する必要があり、CircleCI YAML構成ファイルに直接配置するのは安全ではありません。

CircleCIがリポジトリの変更をリッスンし、環境変数が構成されたら、構成ファイルを作成します。

サンプルアプリケーションリポジトリ内に「+ .circleci +」というディレクトリを作成します。

mkdir ~/do-sample-app/.circleci/

このディレクトリ内で、 `+ config.yml +`という名前のファイルを作成し、お気に入りのエディターで開きます:

nano ~/do-sample-app/.circleci/config.yml

次のコンテンツをファイルに追加し、「++」を必ずDocker Hubユーザー名に置き換えます。

〜/ do-sample-app / .circleci / config.yml

version: 2.1
jobs:
 build:
   docker:
     - image: circleci/buildpack-deps:stretch
   environment:
     IMAGE_NAME: /do-kubernetes-sample-app
   working_directory: ~/app
   steps:
     - checkout
     - setup_remote_docker
     - run:
         name: Build Docker image
         command: |
           docker build -t $IMAGE_NAME:latest .
     - run:
         name: Push Docker Image
         command: |
           echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin
           docker push $IMAGE_NAME:latest
workflows:
 version: 2
 build-master:
   jobs:
     - build:
         filters:
           branches:
             only: master

これにより、 + master +`ブランチへのコミットごとに実行される、 `+ build +`と呼ばれる単一のジョブでワークフローが設定されます。 このジョブは、イメージ `+ circleci / buildpack-deps:stretch +`を使用してステップを実行します。これは、公式の `+ buildpack-deps + Dockerイメージに基づいたCircleCIのイメージですが、Dockerバイナリなどの追加ツールがインストールされています自分自身。

ワークフローには4つのステップがあります。

  • `+ checkout +`はGitHubからコードを取得します。

  • `+ setup_remote_docker `は、ビルドごとにリモートの分離された環境を設定します。 これは、ジョブステップ内で「 docker」コマンドを使用する前に必要です。 これは、手順がdockerイメージ内で実行されているため、 `+ setup_remote_docker +`が別のマシンを割り当ててそこでコマンドを実行するためです。

  • 以前にローカルで行ったように、最初の + run +`ステップでイメージを構築します。 そのために、 `+ environment:+、 `+ IMAGE_NAME +`で宣言した環境変数を使用しています(強調表示されたセクションを独自の情報で変更することを忘れないでください)。

  • 最後の `+ run +`ステップは、認証するプロジェクト設定で構成した環境変数を使用して、イメージをDockerhubにプッシュします。

新しいファイルをリポジトリにコミットし、変更をアップストリームにプッシュします。

cd ~/do-sample-app/
git add .circleci/
git commit -m "add CircleCI config"
git push

これにより、CircleCIで新しいビルドがトリガーされます。 CircleCIワークフローは、イメージを正しく構築し、Docker Hubにプッシュします。

image:https://assets.digitalocean.com/articles/cart_64840/Build.png [成功ビルド情報を含むCircleCIビルドページ]

CircleCIワークフローを作成およびテストしたので、DOCSクラスターを設定して、Docker Hubから最新のイメージを取得し、変更が行われたときに自動的にデプロイできます。

手順8-Kubernetesクラスターでの展開の更新

GitHubの「+ master +」ブランチに変更をプッシュするたびに、アプリケーションイメージが構築されてDocker Hubに送信されるようになったので、新しいイメージを取得して使用するようにKubernetesクラスターの展開を更新します展開のベース。

これを行うには、まずデプロイメントの1つの問題を修正します。現在は、 `+ latest +`タグのある画像に依存しています。 このタグは、使用している画像のバージョンを示しません。 新しいイメージをDocker Hubにプッシュするたびに上書きされるため、そのタグにデプロイを簡単にロックすることはできません。

これについて詳しくは、https://vsupalov.com/docker-latest-tag/ [Dockerの最新タグに依存するアンチパターン]の理由に関する記事をご覧ください。

これを修正するには、最初に +〜/ do-sample-app / .circleci / config.yml`ファイルで + Push Docker Image`ビルドステップに変更を加える必要があります。 ファイルを開きます。

nano ~/do-sample-app/.circleci/config.yml

次に、強調表示された行を「+ Push Docker Image +」ステップに追加します。

〜/ do-sample-app / .circleci / config.yml:16-22

...
     - run:
         name: Push Docker Image
         command: |
           echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin

           docker push $IMAGE_NAME:latest

...

ファイルを保存して終了します。

CircleCIには、デフォルトで設定される特別な環境変数がいくつかあります。 それらの1つは `+ CIRCLE_SHA1 `で、ビルドするコミットのハッシュが含まれています。 `〜/ do-sample-app / .circleci / config.yml +`に加えた変更は、この環境変数を使用して、イメージにビルド元のコミットをタグ付けし、常に最新のビルドに最新のタグをタグ付けします。 これにより、リポジトリに新しい何かをプッシュするときに上書きすることなく、常に特定の画像を使用できます。

次に、そのファイルを指すように展開マニフェストファイルを変更します。 これは、 +〜/ do-sample-app / kube / do-sample-deployment.yml +`内でイメージを `+ / do-kubernetes-sample-app:$ COMMIT_SHA1 +`として設定できれば簡単ですが、 `+ kubectl + `は、 + kubectl apply + を使用する場合、マニフェスト内で変数置換を行いません。 これに対処するには、https://www.gnu.org/software/gettext/manual/html_node/envsubst-Invocation.html [+ envsubst `]を使用できます。 ` envsubst +`は、GNU gettextプロジェクトの一部であるcliツールです。 テキストを渡すことができ、テキスト内で一致する環境変数を持つ変数が見つかった場合は、それぞれの値に置き換えられます。 結果のテキストは、出力として返されます。

これを使用するには、展開を担当する単純なbashスクリプトを作成します。 `〜/ do-sample-app / +`の中に ` scripts +`という新しいフォルダーを作成します:

mkdir ~/do-sample-app/scripts/

そのフォルダー内に、「+ ci-deploy.sh +」という新しいbashスクリプトを作成し、お気に入りのテキストエディターで開きます。

nano ~/do-sample-app/scripts/ci-deploy.sh

その中に次のbashスクリプトを記述します。

〜/ do-sample-app / scripts / ci-deploy.sh

#! /bin/bash
# exit script when any command ran here returns with non-zero exit code
set -e

COMMIT_SHA1=$CIRCLE_SHA1

# We must export it so it's available for envsubst
export COMMIT_SHA1=$COMMIT_SHA1

# since the only way for envsubst to work on files is using input/output redirection,
#  it's not possible to do in-place substitution, so we need to save the output to another file
#  and overwrite the original with that one.
envsubst <./kube/do-sample-deployment.yml >./kube/do-sample-deployment.yml.out
mv ./kube/do-sample-deployment.yml.out ./kube/do-sample-deployment.yml

echo "$KUBERNETES_CLUSTER_CERTIFICATE" | base64 --decode > cert.crt

./kubectl \
 --kubeconfig=/dev/null \
 --server=$KUBERNETES_SERVER \
 --certificate-authority=cert.crt \
 --token=$KUBERNETES_TOKEN \
 apply -f ./kube/

ファイル内のコメントを使用して、このスクリプトを見ていきましょう。 まず、次のものがあります。

set -e

この行は、失敗したコマンドがbashスクリプトの実行を停止することを確認します。 こうすると、1つのコマンドが失敗しても、次のコマンドは実行されません。

COMMIT_SHA1=$CIRCLE_SHA1
export COMMIT_SHA1=$COMMIT_SHA1

これらの行は、CircleCI + $ CIRCLE_SHA1 +`環境変数を新しい名前でエクスポートします。 `+ exporting`を使用してエクスポートせずに変数を宣言したばかりの場合、 + envsubst`コマンドでは表示されません。

envsubst <./kube/do-sample-deployment.yml >./kube/do-sample-deployment.yml.out
mv ./kube/do-sample-deployment.yml.out ./kube/do-sample-deployment.yml

`+ envsubst +`はインプレース置換を実行できません。 つまり、ファイルの内容を読み取ったり、変数をそれぞれの値に置き換えたり、同じファイルに出力を書き戻したりすることはできません。 したがって、出力を別のファイルにリダイレクトし、元のファイルを新しいファイルで上書きします。

echo "$KUBERNETES_CLUSTER_CERTIFICATE" | base64 --decode > cert.crt

CircleCIのプロジェクト設定で以前に作成した環境変数 `+ $ KUBERNETES_CLUSTER_CERTIFICATE `は、実際にはBase64でエンコードされた文字列です。 ` kubectl `で使用するには、その内容をデコードしてファイルに保存する必要があります。 この場合、現在の作業ディレクトリ内の「 cert.crt +」という名前のファイルに保存しています。

./kubectl \
 --kubeconfig=/dev/null \
 --server=$KUBERNETES_SERVER \
 --certificate-authority=cert.crt \
 --token=$KUBERNETES_TOKEN \
 apply -f ./kube/

最後に、 `+ kubectl `を実行しています。 このコマンドには、サービスアカウントのテスト時に実行したものと同様の引数があります。 CircleCIでは現在の作業ディレクトリがプロジェクトのルートフォルダであるため、 ` apply -f。/ kube / `を呼び出しています。 `。/ kube / `は、 `〜/ do-sample-app / kube +`フォルダです。

ファイルを保存し、実行可能であることを確認します。

chmod +x ~/do-sample-app/scripts/ci-deploy.sh

次に、 `+〜/ do-sample-app / kube / do-sample-deployment.yml +`を編集します:

nano ~/do-sample-app/kube/do-sample-deployment.yml

コンテナイメージ値のタグを次のように変更します。

〜/ do-sample-app / kube / do-sample-deployment.yml

     # ...
     containers:
       - name: do-kubernetes-sample-app
         image: /do-kubernetes-sample-app:
         ports:
           - containerPort: 80
             name: http

ファイルを保存して閉じます。 次に、CI設定ファイルにいくつかの新しい手順を追加して、Kubernetesの展開を更新する必要があります。

お気に入りのテキストエディターで `+〜/ do-sample-app / .circleci / config.yml +`を開きます。

nano ~/do-sample-app/.circleci/config.yml

以前の `+ Push Docker Image +`のすぐ下に、次の新しい手順を記述します。

〜/ do-sample-app / .circleci / config.yml

...
     - run:
         name: Install envsubst
         command: |
           sudo apt-get update && sudo apt-get -y install gettext-base
     - run:
         name: Install kubectl
         command: |
           curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
           chmod u+x ./kubectl
     - run:
         name: Deploy Code
         command: ./scripts/ci-deploy.sh

最初の2つのステップでは、いくつかの依存関係をインストールします。最初に + envsubst +、次に `+ kubectl `をインストールします。 ` Deploy Code +`ステップは、デプロイスクリプトの実行を担当します。

Kubernetesの展開に実際に変更が反映されるようにするには、 `+ index.html +`を編集します。 HTMLを次のような他の何かに変更します。

〜/ do-sample-app / index.html

<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
 Automatic Deployment is Working!
</body>

上記の変更を保存したら、変更したすべてのファイルをリポジトリにコミットし、変更をアップストリームにプッシュします。

cd ~/do-sample-app/
git add --all
git commit -m "add deploy script and add new steps to circleci config"
git push

CircleCIで新しいビルドが実行され、Kubernetesクラスターに変更が正常にデプロイされます。

ビルドが完了するのを待ってから、前に実行したのと同じコマンドを実行します。

kubectl port-forward $(kubectl get pod --selector="app=do-kubernetes-sample-app" --output jsonpath='{.items[0].metadata.name}') 8080:80

URL `+ localhost:8080 `でブラウザを開くか、 ` curl +`リクエストを行って、すべてが機能していることを確認します。 更新されたHTMLが表示されます。

curl localhost:8080

次の出力が表示されます。

Output<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
 Automatic Deployment is Working!
</body>

おめでとうございます、CircleCIで自動展開を設定しました!

結論

これは、CircleCIを使用してDigitalOcean Kubernetesに展開する方法に関する基本的なチュートリアルでした。 ここから、さまざまな方法でパイプラインを改善できます。 最初にできることは、それぞれが異なるKubernetesクラスターまたは異なる名前空間にデプロイする複数のデプロイメントに対して単一の `+ build +`ジョブを作成することです。 これは、開発/ステージング/実稼働環境用に異なるGitブランチがある場合に非常に役立ち、デプロイメントが常に分離されるようにします。

`+ buildpack-deps `を使用する代わりに、CircleCIで使用する独自のイメージを作成することもできます。 このイメージはそれに基づいている可能性がありますが、既に ` kubectl `と ` envsubst +`の依存関係がインストールされている可能性があります。

KubernetesのCI / CDの詳細については、https://www.digitalocean.com/community/tutorial_series/webinar-series-ci-cd-on-kubernetes [CI / CDのチュートリアルをご覧ください。 Kubernetes Webinar Series]、またはKubernetesのアプリの詳細については、https://www.digitalocean.com/community/tutorials/modernizing-applications-for-kubernetes [Kubernetesのアプリケーションの近代化]を参照してください。

Related