OpenShiftでStatefulSetを使ってみる
OpenShift 全部俺 Advent Calendar 2017
今までは普通のデプロイメントを利用していましたが、今回はちょっと特殊な性格を持つStatefulSetを使ってみましょう。StatefulSetのレプリカは連番のsuffixが付与され、スケール時の順序制御があったりvolumeClaimTemplatesによる個々のPodへそれぞれPVを割り当てたりできます。主にクラスタ系の分散前提のソフトウェアに利用されます。
https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
StatefulSetはKubernetes 1.8の時点でbeta機能であり、OpenShiftでも3.5から含まれてはいますがまだフルサポートされていません。
いつものRubyプロジェクトをベースにします。
$ oc new-project test-ruby $ oc new-app http://github.com/nekop/hello-sinatra $ oc get all NAME TYPE FROM LATEST buildconfigs/hello-sinatra Source Git 1 NAME TYPE FROM STATUS STARTED DURATION builds/hello-sinatra-1 Source Git@cf28c79 Complete 13 minutes ago 47s NAME DOCKER REPO TAGS UPDATED imagestreams/hello-sinatra docker-registry.default.svc:5000/test-ruby/hello-sinatra latest 12 minutes ago NAME REVISION DESIRED CURRENT TRIGGERED BY deploymentconfigs/hello-sinatra 1 1 1 config,image(hello-sinatra:latest) NAME READY STATUS RESTARTS AGE po/hello-sinatra-1-build 0/1 Completed 0 13m po/hello-sinatra-1-s2ls7 1/1 Running 0 12m NAME DESIRED CURRENT READY AGE rc/hello-sinatra-1 1 1 1 12m NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc/hello-sinatra 172.30.82.101 <none> 8080/TCP 13m
ここでビルドされたイメージをデプロイするStatefulSetを作ってみましょう。まだbeta機能なのでyamlを直接記述する必要があります。
$ cat <<EOF | oc create -f - apiVersion: apps/v1beta1 kind: StatefulSet metadata: name: hello-sinatra-ss spec: replicas: 2 serviceName: hello-sinatra-ss template: metadata: labels: app: hello-sinatra-ss spec: containers: - image: docker-registry.default.svc:5000/test-ruby/hello-sinatra:latest imagePullPolicy: Always name: hello-sinatra-ss ports: - containerPort: 8080 protocol: TCP resources: {} --- apiVersion: v1 kind: Service metadata: labels: app: hello-sinatra-ss name: hello-sinatra-ss spec: ports: - name: 8080-tcp port: 8080 protocol: TCP targetPort: 8080 selector: app: hello-sinatra-ss EOF
これでStatefulSetが作成され、指定した通りレプリカが2つ起動しています。
$ oc get all NAME TYPE FROM LATEST buildconfigs/hello-sinatra Source Git 1 NAME TYPE FROM STATUS STARTED DURATION builds/hello-sinatra-1 Source Git@cf28c79 Complete About a minute ago 47s NAME DOCKER REPO TAGS UPDATED imagestreams/hello-sinatra docker-registry.default.svc:5000/test-ruby/hello-sinatra latest About a minute ago NAME REVISION DESIRED CURRENT TRIGGERED BY deploymentconfigs/hello-sinatra 1 1 1 config,image(hello-sinatra:latest) NAME READY STATUS RESTARTS AGE po/hello-sinatra-1-build 0/1 Completed 0 1m po/hello-sinatra-1-s2ls7 1/1 Running 0 1m po/hello-sinatra-ss-0 1/1 Running 0 12s po/hello-sinatra-ss-1 1/1 Running 0 9s NAME DESIRED CURRENT READY AGE rc/hello-sinatra-1 1 1 1 1m NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc/hello-sinatra 172.30.82.101 <none> 8080/TCP 1m svc/hello-sinatra-ss 172.30.165.8 <none> 8080/TCP 12s NAME DESIRED CURRENT AGE statefulsets/hello-sinatra-ss 2 2 12s
OpenShiftのs2iイメージをカスタマイズする
OpenShift 全部俺 Advent Calendar 2017
昨日は忘年会でした。全部俺 Advent Calendarがすごく大変そう、と言われましたが各エントリ20分程度で書いていますし、そうなるように内容を調整しています。例えば昨日のエントリは17時くらいに同僚に何書いて欲しい?と聞いてから最新の情報をちょっと調べて書いて飲みに行った、くらいのノリです。
今日はデフォルトのs2iイメージをカスタマイズしてみましょう。例ではRubyを利用します。
$ oc new-project test-custom-s2i $ oc new-app http://github.com/nekop/hello-sinatra $ oc get all oc NAME TYPE FROM LATEST buildconfigs/hello-sinatra Source Git 1 NAME TYPE FROM STATUS STARTED DURATION builds/hello-sinatra-1 Source Git@cf28c79 Running 49 seconds ago NAME DOCKER REPO TAGS UPDATED imagestreams/hello-sinatra docker-registry.default.svc:5000/test-custom-s2i/hello-sinatra NAME REVISION DESIRED CURRENT TRIGGERED BY deploymentconfigs/hello-sinatra 0 1 0 config,image(hello-sinatra:latest) NAME READY STATUS RESTARTS AGE po/hello-sinatra-1-build 1/1 Running 0 49s
oc describe bc hello-sinatra
、そしてoc describe is ruby -n openshift
と追っていくと、利用されているImageStreamruby:2.4
はregistry.access.redhat.com/rhscl/ruby-24-rhel7:latest
を参照していることがわかります。
このイメージをDockerfileビルドを利用してカスタマイズしていきます。今回は単純にtouch /foobar
などとしてみます。
cat <<EOF | oc new-build --dockerfile=- --to=custom-ruby FROM registry.access.redhat.com/rhscl/ruby-24-rhel7:latest USER root RUN touch /foobar USER 1001 EOF
ビルドが開始されます。
$ oc get all NAME TYPE FROM LATEST buildconfigs/custom-ruby Docker Dockerfile 1 buildconfigs/hello-sinatra Source Git 1 NAME TYPE FROM STATUS STARTED DURATION builds/custom-ruby-1 Docker Dockerfile Pending builds/hello-sinatra-1 Source Git@cf28c79 Complete 10 minutes ago 1m3s NAME DOCKER REPO TAGS UPDATED imagestreams/custom-ruby docker-registry.default.svc:5000/test-custom-s2i/custom-ruby imagestreams/hello-sinatra docker-registry.default.svc:5000/test-custom-s2i/hello-sinatra latest 9 minutes ago imagestreams/ruby-24-rhel7 docker-registry.default.svc:5000/test-custom-s2i/ruby-24-rhel7 latest 5 seconds ago NAME REVISION DESIRED CURRENT TRIGGERED BY deploymentconfigs/hello-sinatra 1 1 1 config,image(hello-sinatra:latest) NAME READY STATUS RESTARTS AGE po/custom-ruby-1-build 0/1 Init:0/1 0 4s po/hello-sinatra-1-build 0/1 Completed 0 10m po/hello-sinatra-1-ddx5v 1/1 Running 0 9m NAME DESIRED CURRENT READY AGE rc/hello-sinatra-1 1 1 1 9m NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc/hello-sinatra 172.30.223.174 <none> 8080/TCP 10m
ビルドが終わったらbc/hello-sinatra
のspec.strategy.sourceStragtegyのruby:2.4
をcustom-ruby:latest
に変更します。これでカスタマイズしたs2iイメージが利用されます。
$ oc edit bc/hello-sinatra sourceStrategy: from: kind: ImageStreamTag name: ruby:2.4 namespace: openshift
変更後はこうなります。
sourceStrategy: from: kind: ImageStreamTag name: custom-ruby:latest
BuildConfigはConfigChange triggerがデフォルトで有効になっているので、ビルドが自動的に開始され、レジストリにpushされ、DeploymentConfigのImageChange triggerが発動してデプロイされます。
$ oc get all NAME TYPE FROM LATEST buildconfigs/custom-ruby Docker Dockerfile 1 buildconfigs/hello-sinatra Source Git 2 NAME TYPE FROM STATUS STARTED DURATION builds/custom-ruby-1 Docker Dockerfile Complete 6 minutes ago 54s builds/hello-sinatra-1 Source Git@cf28c79 Complete 16 minutes ago 1m3s builds/hello-sinatra-2 Source Git@cf28c79 Complete 4 minutes ago 19s NAME DOCKER REPO TAGS UPDATED imagestreams/custom-ruby docker-registry.default.svc:5000/test-custom-s2i/custom-ruby latest 5 minutes ago imagestreams/hello-sinatra docker-registry.default.svc:5000/test-custom-s2i/hello-sinatra latest 3 minutes ago imagestreams/ruby-24-rhel7 docker-registry.default.svc:5000/test-custom-s2i/ruby-24-rhel7 latest 6 minutes ago NAME REVISION DESIRED CURRENT TRIGGERED BY deploymentconfigs/hello-sinatra 2 1 1 config,image(hello-sinatra:latest) NAME READY STATUS RESTARTS AGE po/custom-ruby-1-build 0/1 Completed 0 6m po/hello-sinatra-1-build 0/1 Completed 0 16m po/hello-sinatra-2-build 0/1 Completed 0 4m po/hello-sinatra-2-t4dpb 1/1 Running 0 3m NAME DESIRED CURRENT READY AGE rc/hello-sinatra-1 0 0 0 15m rc/hello-sinatra-2 1 1 1 3m NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc/hello-sinatra 172.30.223.174 <none> 8080/TCP 16m
新しくデプロイされたコンテナに入ると、ちゃんとカスタマイズが反映されています。
$ oc rsh dc/hello-sinatra ls -la /foobar -rw-r--r--. 1 root root 0 Dec 13 08:41 /foobar
OpenShiftのRBACを完全に理解する
OpenShift 全部俺 Advent Calendar 2017
よくわかりにくいと言われがちなOpenShift / KubernetesのRBACについて書いてみましょう。RBACは元々OpenShiftで実装され、それを元にKubernetes側へ実装された経緯があり、OpenShiftのclusterrole
というリソースオブジェクトとKubernetesのclusterrole
リソースの短縮名が衝突してしまっています。そのため、OpenShift側ではclusterrole.rbac
という名前でリソースを指定する必要があります。ちなみに省略しないリソース名はそれぞれclusterrole.authorization.openshift.io
とclusterrole.rbac.authorization.k8s.io
です。
さて本題。事前に定義されているロールの一覧はoc get clusterrole.rbac
で取得できます。
$ oc get clusterrole.rbac NAME AGE admin 12d asb-access 12d asb-auth 12d basic-user 12d cluster-admin 12d cluster-debugger 12d cluster-reader 12d cluster-status 12d edit 12d hawkular-metrics-admin 12d management-infra-admin 12d namespace-viewer 12d registry-admin 12d registry-editor 12d registry-viewer 12d sar-creator 12d self-access-reviewer 12d self-provisioner 12d service-catalog-controller 12d servicecatalog-serviceclass-viewer 12d storage-admin 12d sudoer 12d system:auth-delegator 12d system:basic-user 12d system:build-controller 12d system:build-strategy-custom 12d system:build-strategy-docker 12d system:build-strategy-jenkinspipeline 12d system:build-strategy-source 12d system:certificate-signing-controller 12d system:controller:attachdetach-controller 12d system:controller:certificate-controller 12d system:controller:cronjob-controller 12d system:controller:daemon-set-controller 12d system:controller:deployment-controller 12d system:controller:disruption-controller 12d system:controller:endpoint-controller 12d system:controller:generic-garbage-collector 12d system:controller:horizontal-pod-autoscaler 12d system:controller:job-controller 12d system:controller:namespace-controller 12d system:controller:node-controller 12d system:controller:persistent-volume-binder 12d system:controller:pod-garbage-collector 12d system:controller:replicaset-controller 12d system:controller:replication-controller 12d system:controller:resourcequota-controller 12d system:controller:route-controller 12d system:controller:service-account-controller 12d system:controller:service-controller 12d system:controller:statefulset-controller 12d system:controller:ttl-controller 12d system:daemonset-controller 12d system:deployer 12d system:deployment-controller 12d system:deploymentconfig-controller 12d system:discovery 12d system:disruption-controller 12d system:endpoint-controller 12d system:garbage-collector-controller 12d system:gc-controller 12d system:heapster 12d system:hpa-controller 12d system:image-auditor 12d system:image-builder 12d system:image-pruner 12d system:image-puller 12d system:image-pusher 12d system:image-signer 12d system:job-controller 12d system:kube-aggregator 12d system:kube-controller-manager 12d system:kube-dns 12d system:kube-scheduler 12d system:master 12d system:namespace-controller 12d system:node 12d system:node-admin 12d system:node-bootstrapper 12d system:node-problem-detector 12d system:node-proxier 12d system:node-reader 12d system:oauth-token-deleter 12d system:openshift:controller:build-config-change-controller 12d system:openshift:controller:build-controller 12d system:openshift:controller:cluster-quota-reconciliation-controller 12d system:openshift:controller:deployer-controller 12d system:openshift:controller:deploymentconfig-controller 12d system:openshift:controller:horizontal-pod-autoscaler 12d system:openshift:controller:image-import-controller 12d system:openshift:controller:image-trigger-controller 12d system:openshift:controller:origin-namespace-controller 12d system:openshift:controller:pv-recycler-controller 12d system:openshift:controller:resourcequota-controller 12d system:openshift:controller:sdn-controller 12d system:openshift:controller:service-ingress-ip-controller 12d system:openshift:controller:service-serving-cert-controller 12d system:openshift:controller:serviceaccount-controller 12d system:openshift:controller:serviceaccount-pull-secrets-controller 12d system:openshift:controller:template-instance-controller 12d system:openshift:controller:template-service-broker 12d system:openshift:controller:unidling-controller 12d system:openshift:templateservicebroker-client 12d system:persistent-volume-provisioner 12d system:registry 12d system:replicaset-controller 12d system:replication-controller 12d system:router 12d system:scope-impersonation 12d system:sdn-manager 12d system:sdn-reader 12d system:statefulset-controller 12d system:webhook 12d view 12d
なんだかすごくいっぱい出てきましたが、system:
とついているものはシステムコンポーネントで利用されているロールで利用者視点では真っ先に無視して構わないものです。除外してみます。
$ oc get clusterrole.rbac | grep -v system: NAME AGE admin 12d asb-access 12d asb-auth 12d basic-user 12d cluster-admin 12d cluster-debugger 12d cluster-reader 12d cluster-status 12d edit 12d hawkular-metrics-admin 12d management-infra-admin 12d namespace-viewer 12d registry-admin 12d registry-editor 12d registry-viewer 12d sar-creator 12d self-access-reviewer 12d self-provisioner 12d service-catalog-controller 12d servicecatalog-serviceclass-viewer 12d storage-admin 12d sudoer 12d view 12d
いくつかまだOpenShiftが利用する目的のロールであり利用者には無関係なロールがあるものの、だいぶすっきりしました。
各ロールが実際に何ができるかはdescribeすればわかります。たとえばnamespace-viewer
はnamespace
オブジェクトのget list watch
が許可されているロールです。
$ oc describe clusterrole.rbac namespace-viewer Name: namespace-viewer Labels: <none> Annotations: <none> PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- namespaces [] [] [get list watch]
カスタムのロールを作るときにResourcesやVerbsに何が指定できるかはoc describe clusterrole.rbac
などで全出力を見ればわかるでしょう。カスタムロールはプロジェクト(namespace)固有のものはrole.rbac
として、クラスタ全体で利用したいロールは管理者権限でclusterrole.rbac
として作成します。
ロールの割り当て状況はoc get clusterrolebinding.rbac -o wide
を確認するとわかります。割り当てられていないロールは非表示となるので注意しましょう。以下system:
を除外した結果です。
$ oc get clusterrolebinding.rbac -o wide | grep -v system: NAME AGE ROLE USERS GROUPS SERVICEACCOUNTS admin 12d admin openshift-infra/template-instance-controller, kube-service-catalog/default, openshift-ansible-service-broker/asb asb-access 12d asb-access openshift-ansible-service-broker/asb-client asb-auth 12d asb-auth openshift-ansible-service-broker/asb hawkular-metrics-admin 12d hawkular-metrics-admin management-infra/management-admin management-infra-admin 12d management-infra-admin management-infra/management-admin service-catalog-controller-binding 12d service-catalog-controller kube-service-catalog/service-catalog-controller service-catalog-controller-namespace-viewer-binding 12d namespace-viewer kube-service-catalog/service-catalog-controller service-catalog-namespace-viewer-binding 12d namespace-viewer kube-service-catalog/service-catalog-apiserver service-catalog-sar-creator-binding 12d sar-creator kube-service-catalog/service-catalog-apiserver
User, Group, Service Accountというのが出てきました。ユーザは一般的なユーザ、およびシステムユーザが含まれます。グループは一般的なグループ、システムグループ、特殊なシステムグループであるバーチャルグループがあります。
system:admin
などのシステムユーザやシステムグループのドキュメントや一覧は用意されていませんが、なんとなく名前で役割はわかると思います。これらはソースコード中にハードコードされているので、oc get user
, oc get group
では表示されず、上記のclusterrolebinding.rbac
の出力が唯一の手掛かりとなります。
system:authenticated
やsystem:unauthenticated
は名前の通り、認証済みユーザ、認証していないユーザを表すバーチャルシステムグループです。これを利用して、例えばsystem:unauthenticated
にregistry-viewer
を付与すると、そのプロジェクトのコンテナイメージは認証なしでpullできる状態となります。
Userは人間が操作するユーザに割り当てるのに対し、Service Account (SA)は、Podに割り当てるユーザです。権限設定が必要なPodや、tokenを抜き出して外部から操作したりといった各種自動化などに利用されます。たとえば各プロジェクトにはdefault
, builder
, deployer
というSAが自動的に作成され、deployer
にはプロジェクトのロールとしてsystem:deployer
が設定されます。これはoc get rolebinding.rbac -o wide
で確認できます。確認するとわかりますが、Podがデフォルトで利用するSAであるdefault
は初期状態ではロールが割り当てられていない一般ユーザとなり、Kubernetes APIへのアクセスは一切できません。
一般的に利用されるロールを軽く説明します。
cluster-admin
- クラスタ管理者権限。一般ユーザに付与するには
oc adm policy add-cluster-role-to-user cluster-admin USERNAME
。
- クラスタ管理者権限。一般ユーザに付与するには
cluster-reader
view
,edit
,admin
registry-viewer
,registry-editor
- プロジェクト内のコンテナイメージのpullおよびpull/push権限。別プロジェクトのSAに付与して利用する。
というわけで、以下の4つさえ押さえておけばRBAC完璧です。
OpenShiftのPipelineビルドで利用するイメージをカスタマイズする
OpenShift 全部俺 Advent Calendar 2017
Google Home買いました。日本語設定でいろいろやってみて、3歳児が「おーけーぐるぐる、てべりをちゅけてください、おねがいします!」と話しかけてるのを一通り楽しんでから英語設定にスイッチして使ってます。これで子供が英語覚えたりするかな。まぁしないだろうな。
前回Jenkins PipelineジョブをSlaveとなる別のPodで実行しました。今回はこのslave podをカスタマイズしてみましょう。ドキュメントは以下のURLです。
https://docs.openshift.org/3.11/using_images/other_images/jenkins.html
https://github.com/jenkinsci/kubernetes-plugin
config.xml
にデフォルトの定義maven
とnode
があるので、それをコピーして新しい設定を作成します。適当にgrepして一つ目を取り出してみます。ConfigMapに突っ込むファイルはCRLFだとEditするときにひどいことになるのでLFに変換します。
$ oc rsh dc/jenkins cat /var/lib/jenkins/config.xml | grep -m1 -A33 PodTemplate | perl -pe 's/^\s{8}//' | dos2unix > pod-template.xml
中身はmaven
のもので、以下のような定義となっています。
<org.csanchez.jenkins.plugins.kubernetes.PodTemplate> <inheritFrom></inheritFrom> <name>maven</name> <privileged>false</privileged> <alwaysPullImage>false</alwaysPullImage> <instanceCap>2147483647</instanceCap> <slaveConnectTimeout>0</slaveConnectTimeout> <idleMinutes>0</idleMinutes> <label>maven</label> <serviceAccount>jenkins</serviceAccount> <nodeSelector></nodeSelector> <customWorkspaceVolumeEnabled>false</customWorkspaceVolumeEnabled> <volumes/> <containers> <org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate> <name>jnlp</name> <image>openshift/jenkins-slave-maven-centos7</image> <privileged>false</privileged> <alwaysPullImage>false</alwaysPullImage> <workingDir>/tmp</workingDir> <command></command> <args>${computer.jnlpmac} ${computer.name}</args> <ttyEnabled>false</ttyEnabled> <resourceRequestCpu></resourceRequestCpu> <resourceRequestMemory></resourceRequestMemory> <resourceLimitCpu></resourceLimitCpu> <resourceLimitMemory></resourceLimitMemory> <envVars/> </org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate> </containers> <envVars/> <annotations/> <imagePullSecrets/> </org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
name
が作成されるslave pod名、label
がPipelineで指定するslaveのラベル名になっています。
両方custom-maven
に変更して、環境変数を追加してビルドしてみましょう。
<org.csanchez.jenkins.plugins.kubernetes.PodTemplate> <inheritFrom></inheritFrom> <name>custom-maven</name> <privileged>false</privileged> <alwaysPullImage>false</alwaysPullImage> <instanceCap>2147483647</instanceCap> <slaveConnectTimeout>0</slaveConnectTimeout> <idleMinutes>0</idleMinutes> <label>custom-maven</label> <serviceAccount>jenkins</serviceAccount> <nodeSelector></nodeSelector> <customWorkspaceVolumeEnabled>false</customWorkspaceVolumeEnabled> <volumes/> <containers> <org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate> <name>jnlp</name> <image>openshift/jenkins-slave-maven-centos7</image> <privileged>false</privileged> <alwaysPullImage>false</alwaysPullImage> <workingDir>/tmp</workingDir> <command></command> <args>${computer.jnlpmac} ${computer.name}</args> <ttyEnabled>false</ttyEnabled> <resourceRequestCpu></resourceRequestCpu> <resourceRequestMemory></resourceRequestMemory> <resourceLimitCpu></resourceLimitCpu> <resourceLimitMemory></resourceLimitMemory> <envVars> <org.csanchez.jenkins.plugins.kubernetes.PodEnvVar> <key>foo</key> <value>bar</value> </org.csanchez.jenkins.plugins.kubernetes.PodEnvVar> </envVars> </org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate> </containers> <envVars/> <annotations/> <imagePullSecrets/> </org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
role=jenkins-slave
というラベルが付与されているConfigMapに入れるとOpenShift Jenkins Sync Pluginが勝手に反映してくれるようになっています。
$ vi pod-template.xml $ oc create configmap jenkins-slave --from-file=pod-template.xml $ oc label configmap jenkins-slave role=jenkins-slave $ oc start-build test-pipeline
これで生成されたcustom-maven-XXXXというPodではfoo=bar
という環境変数が設定されている状態となります。Pipelineでsh "echo $foo"
など実行することで確認できます。
OpenShiftでJenkins Pipelineビルドを利用する
OpenShift 全部俺 Advent Calendar 2017
OpenShiftにはソースコードからビルドするs2iビルド、Dockerfileを利用してビルドするDockerビルドの他にJenkinsを利用したPipelineビルドというのがあります。s2iビルドやDockerビルドはコンテナイメージを生成してpushする、というビルドですが、PipelineビルドはJenkinsで実行する、という少し性格の異なるビルドになっています。
PipelineビルドもJenkinsfileがあるGit URLをoc new-app
で渡すことができますが、Dockerfileのように埋め込むこともできます。個人的にはテスト目的での使用が多いので、埋め込みスタイルを多用しています。
oc new-build
には--dockerfile相当の--jenkinsfileのようなオプションは実装されていないので、Jenkinsfine埋め込みyamlを直接ぶち込みます。
$ cat <<EOF | oc create -f - kind: BuildConfig apiVersion: v1 metadata: name: test-pipeline labels: name: test-pipeline spec: strategy: type: JenkinsPipeline jenkinsPipelineStrategy: jenkinsfile: |- pipeline { agent { label 'maven' } stages { stage('Stage 1') { steps { sh "echo Stage 1" } } stage('Stage 2') { steps { sh "echo Stage 2" } } } } EOF
pipeline、旧syntaxではnode('maven') { sh "echo test" }
で大丈夫なのですが、新しいsyntaxになってからブロックのネストがいっぱいになってちょっと冗長な雰囲気になりました。
例では"echo Stage 1"などの実行しかしていませんが、別のビルドを実行したりイメージを別環境にリリースしたり、統合テストをキックしたりなど好きなことができます。いろいろやっている例が https://blog.openshift.com/building-declarative-pipelines-openshift-dsl-plugin/ に掲載されています。
Pipelineビルドを作成すると、実行のためのJenkinsが自動でデプロイされます。
$ oc get all NAME TYPE FROM LATEST buildconfigs/test-pipeline JenkinsPipeline 0 NAME REVISION DESIRED CURRENT TRIGGERED BY deploymentconfigs/jenkins 1 1 1 config,image(jenkins:latest) NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD routes/jenkins jenkins-test-jenkins.192.168.42.143.nip.io jenkins <all> edge/Redirect None NAME READY STATUS RESTARTS AGE po/jenkins-1-dl7tq 1/1 Running 0 4m NAME DESIRED CURRENT READY AGE rc/jenkins-1 1 1 1 4m NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc/jenkins 172.30.211.203 <none> 80/TCP 4m svc/jenkins-jnlp 172.30.28.12 <none> 50000/TCP 4m $ oc start-build test-pipeline
Jenkinsのログをみると、agent指定されているのでagentとなる新しいPodをスケジューリングして実行しているのがわかります。
$ oc logs dc/jenkins Dec 08, 2017 9:37:57 AM io.fabric8.jenkins.openshiftsync.BuildConfigWatcher updateJob INFO: Updated job test-jenkins-test-pipeline from BuildConfig NamespaceName{test-jenkins:test-pipeline} with revision: 111669 Dec 08, 2017 9:37:57 AM io.fabric8.jenkins.openshiftsync.BuildSyncRunListener onStarted INFO: starting polling build job/test-jenkins-test-pipeline/1/ Dec 08, 2017 9:38:01 AM org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxResolvingClassLoader$4$1 load WARNING: took 334ms to load/not load jenkins.model.Class from classLoader hudson.PluginManager$UberClassLoader Dec 08, 2017 9:38:16 AM org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud provision INFO: Excess workload after pending Spot instances: 1 Dec 08, 2017 9:38:16 AM org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud provision INFO: Template: Kubernetes Pod Template Dec 08, 2017 9:38:17 AM okhttp3.internal.platform.Platform log INFO: ALPN callback dropped: HTTP/2 is disabled. Is alpn-boot on the boot class path? Dec 08, 2017 9:38:17 AM hudson.slaves.NodeProvisioner$StandardStrategyImpl apply INFO: Started provisioning Kubernetes Pod Template from openshift with 1 executors. Remaining excess workload: 0 Dec 08, 2017 9:38:18 AM okhttp3.internal.platform.Platform log INFO: ALPN callback dropped: HTTP/2 is disabled. Is alpn-boot on the boot class path? Dec 08, 2017 9:38:18 AM org.csanchez.jenkins.plugins.kubernetes.ProvisioningCallback call INFO: Created Pod: maven-vb87g in namespace test-jenkins Dec 08, 2017 9:38:18 AM org.csanchez.jenkins.plugins.kubernetes.ProvisioningCallback call INFO: Waiting for Pod to be scheduled (0/100): maven-vb87g Dec 08, 2017 9:38:24 AM okhttp3.internal.platform.Platform log INFO: ALPN callback dropped: HTTP/2 is disabled. Is alpn-boot on the boot class path? Dec 08, 2017 9:38:24 AM org.csanchez.jenkins.plugins.kubernetes.ProvisioningCallback call INFO: Container is waiting maven-vb87g [jnlp]: ContainerStateWaiting(message=null, reason=ContainerCreating, additionalProperties={}) Dec 08, 2017 9:38:24 AM org.csanchez.jenkins.plugins.kubernetes.ProvisioningCallback call INFO: Waiting for Pod to be scheduled (1/100): maven-vb87g
このPod maven-vb87g
の中で指定したステップが実行されます。
Pipelineビルドの状況はWebコンソールから確認でき、View Logを押すとJenkinsの画面に遷移してログを確認できます。
次は'maven'となっている部分の説明とカスタマイズについて書く予定です。
OpenShiftでPVの中身を別のPVへ移行する
OpenShift 全部俺 Advent Calendar 2017
OpenShiftやKubernetesでPVを作って使ってたらPVが一杯になってしまったので大きなサイズのPVへ移行したい、であるとか、HDDのPVを使ってたけどSSDのPVに変えよう、というようなデータ移行のユースケースが発生します。
OpenShiftのdocker-reigstyのPVを移行してみましょう。
oc project default ### 現在のPVC名とボリューム名の確認 (この例では registry と registry-storage) oc get pvc ### docker-registryを一旦停止 oc scale dc docker-registry --replicas=0 ### データ移行に利用するno-opコンテナを起動 oc run sleep --image=registry.access.redhat.com/rhel7 -- tail -f /dev/null ### 現在のPVCをno-opコンテナにマウント oc volume dc/sleep --add -t pvc --name=registry --claim-name=registry --mount-path=/old-registry ### 新しいPV/PVCをno-opコンテナにマウント(dynamic provisioning前提、dynamic provisioningがないならPVを事前に設定) oc volume dc/sleep --add -t pvc --name=new-registry --claim-name=new-registry --mount-path=/new-registry --claim-mode=ReadWriteMany --claim-size=400Gi ### no-opコンテナにrsh oc rsh sleep-X-XXXXX ### no-opコンテナ上でデータをrsyncで移行 rsync -avxHAX --progress /old-registry /new-registry ### docker-registryを現在のPVから新しいPVへスイッチ oc volume dc/docker-registry --remove --name=registry-storage --confirm oc volume dc/docker-registry --add -t pvc --name=registry-storage --claim-name=new-registry --mount-path=/registry ### docker-registryを再開 oc scale dc docker-registry --replicas=1
問題なければ古いPVCは消して良いでしょう。
KubernetesだとOpenShiftのoc volumeのようなコマンドが無いと思いますが、新PVCとデータ移行Podをapplyして同じ作業をすれば良いはずです。
他にkubectl cpでデータ吸い出してPV/PVC切り替えて新しいPodに書き戻す、という安直なアプローチもありますが、アプリが動いたままで書き込み途中のデータを吸い出してしまったり、バックアップ後に書き込まれたデータがロストしたり、新しいPodがデータを上書きされる想定ではないので誤動作する、などの可能性があるので注意しましょう。
OpenShiftでDockerfileやバイナリビルド利用してコンテナをビルドする
OpenShift 全部俺 Advent Calendar 2017
昨日はギョウザパーティでした。基本のs2iビルドではソースコードからビルドしましたが、今回はDockerfileを利用します。
ソースコードと同じようにDockerfileが置いてあるGit URLを指定すると同じようにビルドできるのですが、それでは面白くないのでちょっとアドホックなビルドをしてみましょう。
tail -f /dev/null
を実行するコンテナイメージを作成するDockerfileをGitを利用せずにOpenShiftに食べさせてみます。oc new-build
でビルドしてからoc new-app
でImageStreamを指定してアプリケーションを作成という流れになります。
oc new-project test-dockerbuild cat <<EOF > Dockerfile FROM registry.access.redhat.com/rhel CMD tail -f /dev/null EOF cat Dockerfile | oc new-build --dockerfile=- --to=sleep oc logs sleep-1-build -f oc new-app sleep
できました。デプロイされたコンテナを見ると実行されていますね。
$ oc rsh dc/sleep ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND 1000080+ 1 0.0 0.0 4352 352 ? Ss 06:34 0:00 tail -f /dev/nu 1000080+ 16 0.0 0.0 47448 1612 ? Rs+ 06:35 0:00 ps aux
この方式だとDockerfileはBuildConfigに埋め込まれているので、以降内容を編集する場合はoc edit bc
で直接編集できます。
$ oc export bc sleep kind: BuildConfig spec: source: dockerfile: | FROM registry.access.redhat.com/rhel CMD tail -f /dev/null type: Dockerfile
ただし、上記のDockerfile埋め込みだとビルドコンテキストが渡せないので、ファイルをイメージ内にコピーしたりしたいときに困ります。そのような場合はバイナリビルドにしてoc start-build
時にディレクトリをまるごと転送する、というのもできます。
oc new-build --strategy=docker --binary=true --name=$APP_NAME oc start-build $APP_NAME --from-dir=. oc new-app $APP_NAME
バイナリビルドはDockerfileに限らず、s2iのソースツリーでも同じようにGitを経由しないビルドができます。
ちなみにDockerfileを利用したビルドは現状docker daemon内、つまりrootで実行されているためセキュリティレベルとしては最低です。このため、OpenShift OnlineではDockerビルドは無効化されています。そのうちbuildahなどを利用してdocker daemonとは無関係の通常権限でのDockerfileビルドもできるようになるとは思いますが、そこまでしてDockerfile形式を利用しなければならない理由もあまり無いので、より扱いやすいコンテナイメージの記述およびビルド方式が先にサポートされる気もします。