この記事でやること
IBM Cloud Kubernetes Service(以下IKS)に、OSSのTekton(Pipelines / Triggers / Dashboard)を導入し、IBM Cloud Container Registry(ICR)へイメージをビルド&Pushし、さらにIKSへデプロイする最短の“実運用寄り”CI/CD基盤を作る。
Tektonとは(超短く)
TektonはKubernetes上で動くCI/CDフレームワークで、Task / Pipeline / RunといったCRDとしてパイプラインを定義する。Jenkinsなどの“外部CIサーバ”と違い、KubernetesのネイティブなリソースとしてCI/CDを構築できるのが特徴。(Tekton)
なぜIKSにTektonか
IKSは「マネージドKubernetes」なので、以下の組み合わせが噛み合う。
- TektonがKubernetes内で完結 → IKSのスケール/HAをそのまま活用
- ICR(IBM Cloud標準レジストリ)と近い → Push/Pullが速い・権限設計が素直
- Argo CD / FluxなどGitOpsと相性が良い → ビルド=Tekton、デプロイ=GitOpsの分離が簡単
一方で、IKSはクラスタのセキュリティやネットワーク設定が“管理側に寄っている”ので、オンプレK8sのノリで入れると詰まるポイントもある。
全体アーキテクチャ
最低限の構成はこうなる。
-
Tekton Pipelines(必須)
- CRD群、controller、webhook
-
Tekton Triggers(任意)
- GitHub webhookなどのイベントでPipelineRunを作る
-
Tekton Dashboard(任意)
- 監視/UI
-
ICRアクセス用のSecret + ServiceAccount
-
Workspaces(PVC)によるタスク間のソース受け渡し
前提
IKSクラスタ
- Kubernetes v1.28+ を推奨(Tekton Dashboard含む最新版の前提がこのあたり)。(Tekton)
- Classic / VPC どちらでもOK。
ローカル環境
-
ibmcloudCLI -
ibmcloud ksプラグイン -
ibmcloud cr(Container Registry)プラグイン kubectl- (任意)Tekton CLI
tkn
0. IKSへ接続
クラスタ作成は省略。既存クラスタへkubectlを通す。
# ログイン
ibmcloud login
# 対象クラスタを指定
ibmcloud ks cluster config --cluster <CLUSTER_NAME_OR_ID>
# KUBECONFIGが設定されるので確認
kubectl config current-context
kubectl get nodes
1. Tekton Pipelines導入
最もシンプルな“公式リリースYAMLをapply”方式で入れる。IKS側で特別なOperatorは不要。
kubectl create namespace tekton-pipelines
kubectl apply \
--filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml \
--namespace tekton-pipelines
Podsが全部Runningになるまで確認。
kubectl get pods -n tekton-pipelines
kubectl get crd | grep tekton
Tekton Pipelinesのインストール手順はこの形が公式の推奨。(Tekton)
2. IKS向け追加設定(ここが本題)
2-1. Pod Security(restricted環境でも回るようにする)
IKS環境でPod Security Admissionを有効化している場合、Tektonが注入するサイドカーがrestrictedに引っかかることがある。
Tekton側で feature-flag set-security-context=true を入れておくと、restricted準拠のSecurityContextを付加できる。(Tekton)
kubectl get configmap feature-flags -n tekton-pipelines -o yaml
編集(例:set-security-context をtrueへ):
apiVersion: v1
kind: ConfigMap
metadata:
name: feature-flags
namespace: tekton-pipelines
data:
set-security-context: "true"
適用後、controllerを再起動。
kubectl rollout restart deploy tekton-pipelines-controller -n tekton-pipelines
kubectl rollout restart deploy tekton-pipelines-webhook -n tekton-pipelines
なお、Docker-in-Dockerなどprivileged必須TaskはPSA違反で失敗する。ビルドはKaniko/Buildpacksを使う設計に寄せる。(GitHub)
2-2. Workspaces用StorageClass確認
TektonはTask間でソース/成果物を渡すのにWorkspaces(PVC)を使う。
IKSでは標準のStorageClassがクラスタ種別で違う。
kubectl get storageclass
- Classicなら
ibmc-block-gold/ibmc-file-goldなど - VPCなら
ibmc-vpc-block-10iops-tierなど
PipelineRunで明示しない場合、デフォルトSCが使われる。以後のYAMLでは storageClassName を一応指定する。
2-3. ICRにPushできる権限を作る
IKSのServiceAccountはデフォルトではICRへPushできない。
ICR用APIキー → dockerconfig Secret → Pipeline実行SAへ紐付けの順で作る。
(1) ICRのnamespace作成(未作成なら)
ibmcloud cr namespace-add <ICR_NAMESPACE>
(2) APIキー作成
ibmcloud iam api-key-create tekton-icr-key -d "API key for Tekton"
# 出力される apiKey を控える
(3) dockerconfig Secret作成
kubectl create namespace cicd
kubectl create secret docker-registry icr-secret \
--docker-server=jp.icr.io \
--docker-username=iamapikey \
--docker-password=<YOUR_API_KEY> \
--docker-email=<YOUR_EMAIL> \
-n cicd
(4) Tekton実行用ServiceAccount
kubectl apply -n cicd -f - <<'YAML'
apiVersion: v1
kind: ServiceAccount
metadata:
name: pipeline-sa
secrets:
- name: icr-secret
imagePullSecrets:
- name: icr-secret
YAML
このあたりの流れはIBM側のTekton x ICR導入ガイドで基本形になっている。(IBM Developer)
3. Tekton Triggers(任意)
Webhookで回したい場合のみ入れる。
kubectl create namespace tekton-triggers
kubectl apply \
--filename https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml \
-n tekton-triggers
kubectl apply \
--filename https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml \
-n tekton-triggers
4. Tekton Dashboard(任意)
UIが欲しい場合に導入。read-writeは権限が強いので、基本はクローズドネットワーク前提。(Tekton)
kubectl create namespace tekton-dashboard
kubectl apply \
--filename https://storage.googleapis.com/tekton-releases/dashboard/latest/release-full.yaml \
-n tekton-dashboard
Pod確認。
kubectl get pods -n tekton-dashboard
外部公開するならIKSのALB IngressでServiceをPublisherする。
まずServiceを確認。
kubectl get svc -n tekton-dashboard
例:Ingress(パスベース)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tekton-dashboard
namespace: tekton-dashboard
annotations:
kubernetes.io/ingress.class: "public-iks-k8s-nginx"
spec:
rules:
- host: tekton.<YOUR_DOMAIN>
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tekton-dashboard
port:
number: 9097
5. IKSでビルド→ICRへPush→IKSへデプロイ
5-1. Task(Kanikoでビルド)
privileged不要のKanikoタスクを自前で置く。
(Tekton Catalog版でも良いが、ここでは完全に見える形で載せる)
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: kaniko-build
namespace: cicd
spec:
workspaces:
- name: source
params:
- name: IMAGE
type: string
steps:
- name: build-and-push
image: gcr.io/kaniko-project/executor:v1.23.2
workingDir: $(workspaces.source.path)
args:
- --dockerfile=Dockerfile
- --destination=$(params.IMAGE)
- --context=$(workspaces.source.path)
env:
- name: DOCKER_CONFIG
value: /tekton/home/.docker
5-2. Task(kubectlでデプロイ)
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: kubectl-deploy
namespace: cicd
spec:
workspaces:
- name: source
params:
- name: MANIFEST
type: string
default: k8s/deployment.yaml
steps:
- name: apply
image: bitnami/kubectl:1.30
workingDir: $(workspaces.source.path)
script: |
kubectl apply -f $(params.MANIFEST)
5-3. Pipeline
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: app-ci-cd
namespace: cicd
spec:
workspaces:
- name: shared
params:
- name: GIT_URL
type: string
- name: GIT_REV
type: string
default: main
- name: IMAGE
type: string
tasks:
- name: clone
taskRef:
name: git-clone
kind: ClusterTask
params:
- name: url
value: $(params.GIT_URL)
- name: revision
value: $(params.GIT_REV)
workspaces:
- name: output
workspace: shared
- name: build
runAfter: [clone]
taskRef:
name: kaniko-build
params:
- name: IMAGE
value: $(params.IMAGE)
workspaces:
- name: source
workspace: shared
- name: deploy
runAfter: [build]
taskRef:
name: kubectl-deploy
workspaces:
- name: source
workspace: shared
5-4. PipelineRun
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
generateName: app-ci-cd-run-
namespace: cicd
spec:
pipelineRef:
name: app-ci-cd
serviceAccountName: pipeline-sa
params:
- name: GIT_URL
value: https://github.com/<YOUR_ORG>/<YOUR_REPO>.git
- name: GIT_REV
value: main
- name: IMAGE
value: jp.icr.io/<ICR_NAMESPACE>/hello-tekton:latest
workspaces:
- name: shared
volumeClaimTemplate:
spec:
storageClassName: <DEFAULT_STORAGECLASS>
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
適用して実行。
kubectl apply -f tasks-kaniko.yaml
kubectl apply -f task-deploy.yaml
kubectl apply -f pipeline.yaml
kubectl create -f pipelinerun.yaml
tknがあればログ監視が楽。
tkn pipelinerun logs -n cicd -f -L
6. TriggerでGitHub Push起動(概要)
Triggersを入れた場合の最小構成。
- TriggerBinding:pushイベントからparamsを作る
- TriggerTemplate:PipelineRun雛形
- EventListener:受け口Service
EventListenerを外に出すときは、Dashboardと同様にALB IngressかLoadBalancerで公開する。
7. 運用の話
7-1. リソース掃除
PipelineRun / TaskRunは放置すると爆増する。
TektonにはPrunerがないので、CronJobで削除するのが定番。
例:7日より古いRunを削除
kubectl delete pipelinerun,taskrun -n cicd --field-selector=status.completionTime<$(date -d '7 days ago' -Iseconds)
(実際にはスクリプト化推奨)
7-2. アップグレード
TektonはCRD更新が絡むので、コントローラ→CRD→runの順で慎重に。
release.yaml の差分applyで更新するのが基本。
7-3. セキュリティ
- Dashboardはread-onlyか、ネットワークで閉じる
- ICR用APIキーは最小権限
- Kanikoはrootless設定も検討(PSA厳格環境)
8. よくある詰まりどころ
(1) webhookが起動しない/失敗する
- CRD適用順の問題が多い
→tekton-pipelines-webhookのログ確認
kubectl logs deploy/tekton-pipelines-webhook -n tekton-pipelines
(2) Pod SecurityでTaskが落ちる
- privilegedサイドカー/ボリュームが原因
→ Kaniko/Buildpacksへ切り替え
→set-security-context=trueを再確認
(3) ICRへのPushが403
-
pipeline-saにicr-secretが入っていない - APIキーの対象リージョンやnamespaceミス
kubectl describe sa pipeline-sa -n cicd
kubectl get secret icr-secret -n cicd -o yaml
(4) WorkspaceのPVCがPending
-
storageClassNameが存在しない/プロビジョナ未設定 - IKSのボリューム上限に到達
9. アンインストール
検証後はまとめて消す。
kubectl delete ns cicd tekton-pipelines tekton-triggers tekton-dashboard
まとめ
IKS上でTektonを使うと、KubernetesネイティブなCI/CDがそのままマネージド基盤に乗る。
ただし実運用に持っていくには、
- Pod Securityの取り込み
- ICR権限の正しい結線
- Workspaces/PVCの設計
- 公開コンポーネント(Dashboard/Listener)のIngress整理
あたりまでやって初めて“使える状態”になる。
この記事の構成をベースに、TriggersやGitOps(Argo CD)まで広げると、IKS上でのCloud Nativeデリバリースタックが完成する。
by 花村勇輝(Hanamura Yuki)