CircleCIを使用してDigitalOceanKubernetesへのデプロイを自動化する方法
著者は、 Write forDOnationsプログラムの一環として寄付を受け取るためにTechEducationFundを選択しました。
序章
自動展開プロセスを持つことは、スケーラブルで復元力のあるアプリケーションの要件であり、 GitOpsまたはGitベースのDevOpsは、Gitを使用してCI/CDを整理する一般的な方法に急速になりました。 「信頼できる唯一の情報源」としてのリポジトリ。 CircleCI などのツールはGitHubリポジトリと統合されているため、リポジトリに変更を加えるたびにコードを自動的にテストしてデプロイできます。 この種のCI/CDをKubernetesインフラストラクチャの柔軟性と組み合わせると、需要の変化に合わせて簡単に拡張できるアプリケーションを構築できます。
この記事では、CircleCIを使用して、サンプルアプリケーションをDigitalOcean Kubernetes(DOKS)クラスターにデプロイします。 このチュートリアルを読むと、これらの同じ手法を適用して、Dockerイメージとしてビルド可能な他のCI/CDツールをデプロイできるようになります。
前提条件
このチュートリアルに従うには、次のものが必要です。
- DigitalOceanアカウント。DigitalOceanアカウントのサインアップのドキュメントに従って設定できます。
- ワークステーションにインストールされたDocker、およびDockerイメージの構築、削除、実行方法に関する知識。 Ubuntu 20.04にDockerをインストールして使用する方法のチュートリアルに従って、Ubuntu20.04にDockerをインストールできます。
- Kubernetesがどのように機能し、その上にデプロイとサービスを作成する方法に関する知識。 Kubernetesの概要の記事を読むことを強くお勧めします。
- クラスターを制御するコンピューターにインストールされているkubectlコマンドラインインターフェイスツール。
- サンプルアプリケーションイメージの保存に使用されるDockerHubのアカウント。
- GitHubアカウントとGitの基本に関する知識。 チュートリアルシリーズGitの概要:インストール、使用法、ブランチおよび GitHubでプルリクエストを作成する方法に従って、この知識を構築できます。
このチュートリアルでは、Kubernetesバージョン1.22.7
およびkubectl
バージョン1.23.5
を使用します。
ステップ1—DigitalOceanKubernetesクラスターを作成する
注:すでにDigitalOcean Kubernetesクラスターを実行している場合は、このセクションをスキップできます。
この最初のステップでは、サンプルアプリケーションをデプロイするDigitalOcean Kubernetes(DOKS)クラスターを作成します。 ローカルマシンから実行されるkubectl
コマンドは、Kubernetesクラスターから直接情報を変更または取得します。
DigitalOceanアカウントのKubernetesページに移動します。
Kubernetesクラスターの作成をクリックするか、ページの右上にある緑色の Create ボタンをクリックして、ドロップダウンメニューからKubernetesを選択します。
次のページでは、クラスターの詳細を指定します。 でKubernetesバージョンを選択バージョン1.22.7-do.0を選択します。 これが利用できない場合は、最新の推奨バージョンを選択してください。
データセンターリージョンの選択の場合、最も近いリージョンを選択します。 このチュートリアルでは、 SanFranciscoを使用します。
次に、ノードプールを構築するオプションがあります。 Kubernetesでは、ノードはワーカーマシンであり、ポッドの実行に必要なサービスが含まれています。 DigitalOceanでは、各ノードはドロップレットです。 ノードプールは、単一の基本ノードで構成されます。 1GB / 1vCPU 構成を選択し、ノード数を1ノードに変更します。
必要に応じてタグを追加できます。 これは、 DigitalOcean API を使用する場合、またはノードプールをより適切に整理する場合に役立ちます。
名前を選択します。このチュートリアルでは、kubernetes-deployment-tutorial
を使用します。 これにより、次のセクションを読みながら、全体を簡単に理解できるようになります。 最後に、緑色のクラスターの作成ボタンをクリックしてクラスターを作成します。 クラスタの作成が完了するまで待ちます。
クラスタの作成後、クラスタに接続するための手順が表示されます。 自動(推奨)タブの指示に従うか、手動タブでkubeconfigファイルをダウンロードします。 これは、クラスターに対して実行する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 current_kubernetes-deployment-tutorial-kubeconfig.yaml_file_path ~/.kube/config
これで、構成ファイルのパスは~/.kube/config
になります。 これは、コマンドの実行時にkubectl
がデフォルトで読み取るファイルであるため、--kubeconfig
を渡す必要はありません。 次を実行します。
kubectl get pods
次の出力が表示されます。
OutputNo resources found in default namespace.
次に、次のコマンドでクラスターにアクセスします。
kubectl get nodes
クラスタ上のノードのリストを受け取ります。 出力は次のようになります。
OutputNAME STATUS ROLES AGE VERSION pool-upkissrv3-uzm8z Ready <none> 12m v1.22.7
このチュートリアルでは、すべてのkubectl
コマンドとマニフェストファイルにdefault
名前空間を使用します。これらのファイルは、Kubernetesでの作業のワークロードと操作パラメーターを定義するファイルです。 名前空間は、単一の物理クラスター内の仮想クラスターのようなものです。 他の任意の名前空間に変更できます。 必ず--namespace
フラグを使用してkubectl
に渡すか、Kubernetesマニフェストメタデータフィールドで指定してください。 これらは、チームとその実行環境の展開を整理するための優れた方法です。 それらの詳細については、Namespacesに関するKubernetesの公式概要をご覧ください。
この手順を完了すると、クラスターに対してkubectl
を実行できるようになります。 次のステップでは、サンプルアプリケーションを格納するために使用するローカルGitリポジトリを作成します。
ステップ2—ローカルGitリポジトリを作成する
次に、ローカルGitリポジトリでサンプルデプロイメントを構造化します。 また、クラスターで実行するすべてのデプロイに対してグローバルになるいくつかのKubernetesマニフェストを作成します。
注:このチュートリアルはUbuntu 20.04でテストされており、個々のコマンドはこのOSに一致するようにスタイル設定されています。 ただし、ここでのコマンドのほとんどは、変更をほとんどまたはまったく必要とせずに他のLinuxディストリビューションに適用でき、kubectl
などのコマンドはプラットフォームに依存しません。
まず、後で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 ユーザーを使用して、他のServicesからKubernetesクラスターへの認証を行うことはお勧めしません。 外部プロバイダーのキーが危険にさらされると、クラスター全体が危険にさらされます。
代わりに、RBACKubernetes認証モデルの一部である特定のロールを持つ単一のサービスアカウントを使用します。
この承認モデルは、ロールおよびリソースに基づいています。 基本的にクラスター上のユーザーであるサービスアカウントを作成することから始め、次に、クラスター上でアクセスできるリソースを指定するロールを作成します。 最後に、 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つを使用して表されます。 この場合、このリソースはKubernetesAPIバージョンv1
からのものであり(内部的にkubectl
はKubernetesHTTP APIを呼び出してリソースを作成します)、ServiceAccount
です。
metadata
フィールドは、このリソースに関する詳細情報を追加するために使用されます。 この場合、このServiceAccount
にcicd
という名前を付け、default
名前空間に作成します。
これで、次のようにkubectl apply
を実行して、クラスター上にこのサービスアカウントを作成できます。
kubectl apply -f ~/kube-general/
次のような出力が表示されます。
Outputserviceaccount/cicd created
サービスアカウントが機能していることを確認するには、それを使用してクラスターにログインしてみてください。 これを行うには、最初にそれぞれのアクセストークンを取得し、それを環境変数に格納する必要があります。 すべてのサービスアカウントには、Kubernetesが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 preceding-command -o jsonpath='{.data.token}' | base64 --decode
これにより、サービスアカウントトークンのシークレットのみが取得されます。 次に、jsonpath
を使用してトークンフィールドにアクセスし、結果をbase64 --decode
に渡します。 トークンはBase64文字列として保存されるため、これが必要です。 トークン自体はJSONWebトークンです。
これで、cicd
サービスアカウントを使用してポッドの取得を試みることができます。 次のコマンドを実行し、server-from-kubeconfig-file
を、~/.kube/config
(クラスター用にダウンロードした構成ファイル)のserver:
の後にあるサーバーURLに置き換えます。 このコマンドは、このチュートリアルの後半で学習する特定のエラーを表示します。
kubectl --insecure-skip-tls-verify --kubeconfig="/dev/null" --server=server-from-kubeconfig-file --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
リソースを使用する方法です。 前者と後者の違いは、最初の名前空間は単一の名前空間に適用され、もう1つはクラスター全体に有効であるということです。
このチュートリアルでは単一の名前空間を使用しているため、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 APIrbac.authorization.k8s.io/v1
からのものであると言っています。 ロールにcicd
という名前を付け、ServiceAccount
、default
を作成したのと同じ名前空間にロールを作成します。
次に、rules
フィールドがあります。これは、このロールがアクセスできるリソースのリストです。 Kubernetesでは、リソースは、それらが属するAPIグループ、リソースの種類自体、および動詞で表されるそのときに実行できるアクションに基づいて定義されます。 これらの動詞はHTTPの動詞に似ています。
この場合、Role
は、deployments
、services
、 [ X142X]、pods
、jobs
、およびcronjobs
。 これは、次のAPIグループに属するリソースにも適用されます:""
(空の文字列)、apps
、batch
、およびextensions
。 空の文字列は、ルートAPIグループを意味します。 リソースの作成時にapiVersion: v1
を使用する場合は、このリソースがこのAPIグループの一部であることを意味します。
Role
自体は何もしません。 また、 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
です。
注: ClusterRole
を使用した場合は、RoleBinding
の代わりにClusterRoleBinding
を作成する必要があります。 ファイルはほとんど同じです。 唯一の違いは、metadata
内にnamespace
フィールドがないことです。
これらのファイルを作成すると、kubectl apply
を再び使用できるようになります。 次のコマンドを実行して、Kubernetesクラスターにこれらの新しいリソースを作成します。
kubectl apply -f ~/kube-general/
次のような出力が表示されます。
Outputrolebinding.rbac.authorization.k8s.io/cicd created role.rbac.authorization.k8s.io/cicd created serviceaccount/cicd unchanged
ここで、前に実行したコマンドを試してください。
kubectl --insecure-skip-tls-verify --kubeconfig="/dev/null" --server=server-from-kubeconfig-file --token=$TOKEN get pods
ポッドがないため、次の出力が生成されます。
OutputNo resources found in default namespace.
このステップでは、CircleCIで使用するサービスアカウントに、リソースの一覧表示、作成、更新など、クラスターで意味のあるアクションを実行するために必要な承認を与えました。 次に、サンプルアプリケーションを作成します。
ステップ5—サンプルアプリケーションの作成
注:これ以降に作成されるすべてのコマンドとファイルは、前に作成した~/do-sample-app
フォルダーから開始されます。 これは、クラスターにデプロイするサンプルアプリケーションに固有のファイルを作成しているためです。
作成するKubernetesDeployment
は、 Nginx イメージをベースとして使用し、アプリケーションは単純な静的HTMLページになります。 Nginxから直接HTMLを提供することでデプロイメントが機能するかどうかをテストできるため、これは素晴らしいスタートです。 後で説明するように、ローカルaddress:port
に着信するすべてのトラフィックをクラスター上のデプロイメントにリダイレクトして、クラスターが機能しているかどうかをテストできます。
以前に設定したリポジトリ内に、新しいDockerfile
ファイルを作成し、選択したテキストエディタで開きます。
nano ~/do-sample-app/Dockerfile
その上に次のように書いてください。
〜/ do-sample-app / Dockerfile
FROM nginx:1.21 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は、アプリケーションが機能しているかどうかを知らせる簡単なメッセージを表示します。
イメージをビルドして実行することで、イメージが正しいかどうかをテストできます。
まず、次のコマンドを使用してイメージをビルドし、dockerhub-username
を独自のDockerHubユーザー名に置き換えます。 ここでユーザー名を指定する必要があります。これにより、後でDockerHubにプッシュしたときに機能します。
docker build ~/do-sample-app/ -t dockerhub-username/do-kubernetes-sample-app
次に、イメージを実行します。 次のコマンドを使用して、イメージを開始し、ポート8080
のローカルトラフィックをイメージ内のポート80
に転送します。ポートNginxはデフォルトでリッスンします。
docker run --rm -it -p 8080:80 dockerhub-username/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
)を停止し、このイメージをDockerHubアカウントに送信します。 これを行うには、最初にDockerHubにログインします。
docker login
Docker Hubアカウントに関する必要な情報を入力し、次のコマンドでイメージをプッシュします(dockerhub-username
を独自のものに置き換えることを忘れないでください)。
docker push dockerhub-username/do-kubernetes-sample-app
これで、サンプルアプリケーションイメージがDockerHubアカウントにプッシュされました。 次のステップでは、このイメージからDOKSクラスターにデプロイメントを作成します。
ステップ6—Kubernetesのデプロイとサービスを作成する
Dockerイメージを作成して機能させたら、クラスター上でDockerイメージからDeploymentを作成する方法をKubernetesに指示するマニフェストを作成します。
YAMLデプロイメントファイル~/do-sample-app/kube/do-sample-deployment.yml
を作成し、テキストエディターで開きます。
nano ~/do-sample-app/kube/do-sample-deployment.yml
ファイルに次のコンテンツを書き込み、dockerhub-username
をDockerHubのユーザー名に置き換えてください。
〜/ 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: dockerhub-username/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
と呼ばれる単一のコンテナーが含まれています。 そのコンテナのイメージは、以前にビルドしてDockerHubにプッシュしたイメージです。
このYAMLファイルは、このコンテナがポート80
を公開していることをKubernetesに通知し、このポートにhttp
という名前を付けます。
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: do-kubernetes-sample-app
というタグが付いているので、ここで使用しました。 spec.ports
は、このサービスから公開するポッドのコンテナによって公開されるポートです。 ポッドには、ポート80
を公開するhttp
という名前の単一のコンテナーがあるため、ここでは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}')
は、使用したapp
タグに一致するポッドの名前を取得します。 それ以外の場合は、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リポジトリにプッシュします。 これを行うには、最初にdigital-ocean-kubernetes-deploy
という名前のリポジトリをGitHubに作成する必要があります。
デモンストレーションの目的でこのリポジトリをシンプルに保つために、GitHub UIで要求されたときに、README
、license
、または.gitignore
ファイルで新しいリポジトリを初期化しないでください。 これらのファイルは後で追加できます。
リポジトリを作成したら、ローカルリポジトリをGitHub上のリポジトリにポイントします。 これを行うには、CTRL
+ C
を押してkubectl port-forward
を停止し、コマンドラインを元に戻します。次に、次のコマンドを実行して、origin
という新しいリモコンを追加します。 :
cd ~/do-sample-app/ git remote add origin https://github.com/your-github-account-username/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:your-github-account-username/digital-ocean-kubernetes-deploy.git * [new branch] master -> master Branch master set up to track remote branch master from origin.
GitHubリポジトリページに移動すると、そこにあるすべてのファイルが表示されます。 プロジェクトをGitHubに設定すると、CircleCIをCI/CDツールとして設定できるようになります。
ステップ7—CircleCIの構成
このチュートリアルでは、CircleCIを使用して、コードが更新されるたびにアプリケーションのデプロイを自動化するため、GitHubアカウントを使用してCircleCIにログインし、リポジトリを設定する必要があります。
まず、彼らのホームページ https://circleci.com にアクセスし、サインアップを押します。
GitHubを使用しているので、緑色のGitHubでサインアップボタンをクリックします。
CircleCIはGitHubの認証ページにリダイレクトします。 CircleCIは、プロジェクトの構築を開始できるようにするために、アカウントにいくつかの権限が必要です。 これにより、CircleCIは電子メールを取得し、キーとアクセス許可をデプロイしてリポジトリにフックを作成し、SSHキーをアカウントに追加できます。 CircleCIがデータをどのように処理するかについての詳細が必要な場合は、GitHub統合に関するドキュメントを確認してください。
CircleCIを承認すると、プロジェクトページにリダイレクトされます。 ここで、CircleCIでGitHubリポジトリを設定できます。 digital-ocean-kubernetes-deploy
リポジトリのエントリでプロジェクトのセットアップを選択します。 次に、 Faster:スターターCIパイプラインを新しいブランチオプションにコミットするを選択します。 これにより、プロジェクトの新しいcircleci-project-setupブランチが作成されます。
次に、CircleCI設定でいくつかの環境変数を指定します。 プロジェクトの設定を確認するには、ページの右上にあるプロジェクト設定ボタンを選択し、環境変数を選択します。 環境変数の追加を押して、新しい環境変数を作成します。
まず、DOCKERHUB_USERNAME
とDOCKERHUB_PASS
という2つの環境変数を追加します。これらは、後でイメージをDockerHubにプッシュするために必要になります。 値をそれぞれDockerHubのユーザー名とパスワードに設定します。
次に、KUBERNETES_TOKEN
、KUBERNETES_SERVER
、およびKUBERNETES_CLUSTER_CERTIFICATE
の3つを追加します。
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
に渡した文字列になります。 これは、server:
の後に、~/.kube/config
ファイル、またはKubernetesクラスターの初期設定時にDigitalOceanダッシュボードからダウンロードしたファイルkubernetes-deployment-tutorial-kubeconfig.yaml
にあります。
KUBERNETES_CLUSTER_CERTIFICATE
は、~/.kube/config
ファイルでも使用できるはずです。 これは、クラスターに関連するclusters
アイテムのcertificate-authority-data
フィールドです。 長い文字列である必要があります。 必ずすべてコピーしてください。
これらの環境変数のほとんどには機密情報が含まれており、CircleCI YAML構成ファイルに直接配置するのは安全ではないため、これらの環境変数をここで定義する必要があります。
CircleCIがリポジトリの変更をリッスンし、環境変数が構成されたら、構成ファイルを作成します。
サンプルアプリケーションリポジトリ内に.circleci
というディレクトリを作成します。
mkdir ~/do-sample-app/.circleci/
このディレクトリ内に、config.yml
という名前のファイルを作成し、お気に入りのエディタで開きます。
nano ~/do-sample-app/.circleci/config.yml
次のコンテンツをファイルに追加し、dockerhub-username
をDockerHubのユーザー名に置き換えてください。
〜/ do-sample-app / .circleci / config.yml
version: 2.1 jobs: build: docker: - image: circleci/buildpack-deps:bullseye environment: IMAGE_NAME: dockerhub-username/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-deploy-master: jobs: - build: filters: branches: only: master
これにより、ワークフローbuild-deploy-master
が設定され、現在build
という単一のジョブがあります。 このジョブは、master
ブランチへのコミットごとに実行されます。
build
ジョブは、イメージcircleci/buildpack-deps:bullseye
を使用してステップを実行します。これは、公式の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ワークフローは、イメージを正しくビルドしてDockerHubにプッシュします。
CircleCIワークフローを作成してテストしたので、Docker Hubから最新のイメージを取得し、変更が加えられたときに自動的にデプロイするようにDOKSクラスターを設定できます。
ステップ8—Kubernetesクラスターでのデプロイの更新
GitHubのmaster
ブランチに変更をプッシュするたびにアプリケーションイメージがビルドされてDockerHubに送信されるようになったので、Kubernetesクラスターのデプロイを更新して、新しいイメージを取得して使用できるようにします。展開のベースとして。
これを行うには、最初に展開に関する1つの問題を修正します。現在、latest
タグが付いたイメージに依存しています。 このタグは、使用している画像のバージョンを示していません。 新しいイメージをDockerHubにプッシュするたびに上書きされるため、デプロイをそのタグに簡単にロックすることはできません。そのように使用すると、コンテナー化されたアプリケーションの再現性が失われます。
これについて詳しくは、 Vladislav Supalovの記事で、最新のタグに依存することがアンチパターンである理由について読むことができます。
これを修正するには、最初に~/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
... - run: name: Push Docker Image command: | echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin docker tag $IMAGE_NAME:latest $IMAGE_NAME:$CIRCLE_SHA1 docker push $IMAGE_NAME:latest docker push $IMAGE_NAME:$CIRCLE_SHA1 ...
CircleCIには、デフォルトでいくつかの特別な環境変数が設定されています。 それらの1つはCIRCLE_SHA1
で、これには構築中のコミットのハッシュが含まれています。 ~/do-sample-app/.circleci/config.yml
に加えた変更では、この環境変数を使用して、ビルド元のコミットでイメージにタグを付け、常に最新のビルドに最新のタグを付けます。 そうすれば、リポジトリに新しいものをプッシュするときにそれらを上書きすることなく、常に特定のイメージを利用できます。
ファイルを保存して終了します。
次に、デプロイメントマニフェストファイルをそのファイルを指すように変更します。 ~/do-sample-app/kube/do-sample-deployment.yml
内で画像をdockerhub-username/do-kubernetes-sample-app:$COMMIT_SHA1
として設定できる場合、これは小さな変更になりますが、kubectl
は、 [を使用すると、マニフェスト内で変数置換を行いません。 X173X]。 これを説明するために、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 # 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 you will 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
環境変数を新しい名前でエクスポートします。 export
を使用して変数をエクスポートせずに宣言したばかりの場合、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: dockerhub-username/do-kubernetes-sample-app:$COMMIT_SHA1 ports: - containerPort: 80 name: http
ファイルを保存して閉じます。 ここで、CI構成ファイルにいくつかの新しいステップを追加して、Kubernetesでのデプロイを更新する必要があります。
お気に入りのテキストエディタで~/do-sample-app/.circleci/config.yml
を開きます。
nano ~/do-sample-app/.circleci/config.yml
以前に作成したbuild
ジョブのすぐ下に、次の新しいジョブを記述します。
〜/ do-sample-app / .circleci / config.yml
... command: | echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin docker tag $IMAGE_NAME:latest $IMAGE_NAME:$CIRCLE_SHA1 docker push $IMAGE_NAME:latest docker push $IMAGE_NAME:$CIRCLE_SHA1 deploy: docker: - image: circleci/buildpack-deps:bullseye working_directory: ~/app steps: - checkout - 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 ...
新しいdeploy
ジョブの最初の2つのステップは、いくつかの依存関係をインストールすることです。最初にenvsubst
、次にkubectl
です。 Deploy Code
ステップは、デプロイスクリプトの実行を担当します。
次に、このジョブを前に作成したbuild-deploy-master
ワークフローに追加します。 build-deploy-master
ワークフロー構成内で、build
ジョブの既存のエントリの直後に次の新しいエントリを記述します。
〜/ do-sample-app / .circleci / config.yml
... workflows: version: 2 build-deploy-master: jobs: - build: filters: branches: only: master - deploy: requires: - build filters: branches: only: master
これにより、deploy
ジョブがbuild-deploy-master
ワークフローに追加されます。 deploy
ジョブは、master
へのコミットに対してのみ実行され、build
ジョブが完了した後にのみ実行されます。
~/do-sample-app/.circleci/config.yml
の内容は次のようになります。
〜/ do-sample-app / .circleci / config.yml
version: 2.1 jobs: build: docker: - image: circleci/buildpack-deps:bullseye environment: IMAGE_NAME: dockerhub-username/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 tag $IMAGE_NAME:latest $IMAGE_NAME:$CIRCLE_SHA1 docker push $IMAGE_NAME:latest docker push $IMAGE_NAME:$CIRCLE_SHA1 deploy: docker: - image: circleci/buildpack-deps:bullseye working_directory: ~/app steps: - checkout - 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 workflows: version: 2 build-deploy-master: jobs: - build: filters: branches: only: master - deploy: requires: - build filters: branches: only: master
これで、ファイルを保存して終了できます。
変更が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を使用してDigitalOceanKubernetesにデプロイする方法に関する基本的なチュートリアルでした。 ここから、さまざまな方法でパイプラインを改善できます。 最初にできることは、複数のデプロイ用に単一のbuild
ジョブを作成することです。各デプロイメントは、異なるKubernetesクラスターまたは異なる名前空間にデプロイされます。 これは、開発/ステージング/本番環境に異なるGitブランチがあり、デプロイメントが常に分離されていることを確認する場合に役立ちます。
buildpack-deps
を使用する代わりに、CircleCIで使用する独自のイメージを作成することもできます。 このイメージはそれに基づいている可能性がありますが、kubectl
およびenvsubst
の依存関係がすでにインストールされている可能性があります。
KubernetesのCI/CDの詳細については、Kubernetes WebinarSeriesのCI/ CDのチュートリアルをご覧ください。また、Kubernetesのアプリの詳細については、アプリケーションの最新化をご覧ください。 Kubernetes。