nekop's blog

OpenShift / JBoss / WildFly / Infinispanの中の人 http://twitter.com/nekop

OpenShiftのRBACを完全に理解する

OpenShift 全部俺 Advent Calendar 2017

よくわかりにくいと言われがちなOpenShift / KubernetesのRBACについて書いてみましょう。RBACは元々OpenShiftで実装され、それを元にKubernetes側へ実装された経緯があり、OpenShiftのclusterroleというリソースオブジェクトとKubernetesのclusterroleリソースの短縮名が衝突してしまっています。そのため、OpenShift側ではclusterrole.rbacという名前でリソースを指定する必要があります。ちなみに省略しないリソース名はそれぞれclusterrole.authorization.openshift.ioclusterrole.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-viewernamespaceオブジェクトの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:authenticatedsystem:unauthenticatedは名前の通り、認証済みユーザ、認証していないユーザを表すバーチャルシステムグループです。これを利用して、例えばsystem:unauthenticatedregistry-viewerを付与すると、そのプロジェクトのコンテナイメージは認証なしでpullできる状態となります。

https://docs.openshift.com/container-platform/3.7/architecture/additional_concepts/authentication.html#users-and-groups

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
    • クラスタ読み込み権限。Kubernetesクラスタのモニタリングなどを行うservice accountなどに付与するケースが多い
  • view, edit, admin
    • プロジェクトの読み込み、読み書き、管理権限。読み込み権限はKubernetes APIをクエリするようなユーザやSAに、読み書きは追加で変更が必要なユーザやSA、管理権限は権限付与も含めて行えるので、プロジェクトの管理者にしたいユーザに付与します。たとえばoc policy add-role-to-user view -z defaultで、defaultのSAで動作するPodにKubernetes APIのクエリを行う権限が付与できます。
  • registry-viewer, registry-editor
    • プロジェクト内のコンテナイメージのpullおよびpull/push権限。別プロジェクトのSAに付与して利用する。

というわけで、以下の4つさえ押さえておけばRBAC完璧です。

  • clusterrole.rbac
  • clusterrolebinding.rbac
  • role.rbac
    • プロジェクト(namespace)固有のロール
  • rolebinding.rbac
    • プロジェクト(namespace)固有のロール割り当て

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にデフォルトの定義mavennodeがあるので、それをコピーして新しい設定を作成します。適当に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の画面に遷移してログを確認できます。

f:id:nekop:20171208184927p:plain

f:id:nekop:20171208184448p:plain

次は'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形式を利用しなければならない理由もあまり無いので、より扱いやすいコンテナイメージの記述およびビルド方式が先にサポートされる気もします。

OpenShift Container Platform 3.7をシングルノードでインストールする

OpenShift 全部俺 Advent Calendar 2017

商用版のOpenShift Container Platform 3.7をシングルノードでインストールしてみます。

利用する/etc/ansible/hostsファイルの中身はこんな感じです。OpenShift Container Platform 3.6以前ではシングルマスター構成ではmaster-api, master-controllers, etcdが全部一つのプロセスmasterで動作する構成でしたが、管理性向上のため3.7ではこれは廃止され、マルチマスターと同一のプロセス構成になりました。

[OSEv3:children]
masters
etcd
nodes

[OSEv3:vars]
ansible_ssh_user=nekop
ansible_become=true
deployment_type=openshift-enterprise
openshift_master_identity_providers=[{'name': 'allow_all', 'login': 'true', 'challenge': 'true', 'kind': 'AllowAllPasswordIdentityProvider'}]
os_sdn_network_plugin_name=redhat/openshift-ovs-multitenant
openshift_node_kubelet_args={'kube-reserved': ['cpu=100m,memory=100Mi'], 'system-reserved': ['cpu=100m,memory=100Mi'], 'eviction-hard': [ 'memory.available<4%', 'nodefs.available<4%', 'nodefs.inodesFree<4%', 'imagefs.available<4%', 'imagefs.inodesFree<4%' ], 'eviction-soft': [ 'memory.available<8%', 'nodefs.available<8%', 'nodefs.inodesFree<8%', 'imagefs.available<8%', 'imagefs.inodesFree<8%' ], 'eviction-soft-grace-period': [ 'memory.available=1m30s', 'nodefs.available=1m30s', 'nodefs.inodesFree=1m30s', 'imagefs.available=1m30s', 'imagefs.inodesFree=1m30s' ]}
openshift_disable_check=memory_availability,disk_availability
openshift_master_default_subdomain=apps.example.com

[masters]
s37.example.com

[etcd]
s37.example.com

[nodes]
s37.example.com openshift_node_labels="{'region': 'infra'}" openshift_schedulable=true

rootでssh-copy-idしてあるstatic IPを持つRHEL 7.4 VMからスタートし、インストールの事前準備はこんな感じで流しています。dockerのstorage driverはoverlay2を指定します。

HOSTNAME=s37.example.com
RHSM_USERNAME=
RHSM_PASSWORD=
RHSM_POOLID=
OPENSHIFT_VERSION=3.7

hostnamectl set-hostname $HOSTNAME
timedatectl set-timezone Asia/Tokyo
adduser -G wheel nekop
cat << EOM > /etc/sudoers.d/wheel
%wheel ALL=(ALL) NOPASSWD: ALL
Defaults:%wheel !requiretty
EOM
mkdir /home/nekop/.ssh/
cp -a /root/.ssh/authorized_keys /home/nekop/.ssh/
chown nekop.nekop -R /home/nekop/.ssh/
subscription-manager register --username=$RHSM_USERNAME --password=$RHSM_PASSWORD
subscription-manager attach --pool $RHSM_POOLID
subscription-manager repos --disable=*
subscription-manager repos \
     --enable=rhel-7-server-rpms \
     --enable=rhel-7-server-extras-rpms \
     --enable=rhel-7-server-optional-rpms \
     --enable=rhel-7-server-rh-common-rpms \
     --enable=rhel-7-fast-datapath-rpms \
     --enable=rhel-7-server-ose-$OPENSHIFT_VERSION-rpms

yum update -y
yum install chrony wget git net-tools bind-utils iptables-services bridge-utils nfs-utils sos sysstat bash-completion lsof tcpdump yum-utils yum-cron docker atomic-openshift-utils -y
sed -i 's/DOCKER_STORAGE_OPTIONS=/DOCKER_STORAGE_OPTIONS="--storage-driver overlay2"/' /etc/sysconfig/docker-storage
systemctl enable chronyd docker
reboot

これでインストールの準備が整ったので、ログインしなおした後にssh keyを用意してssh-copy-idしてansibleします。問題なければ再度確認も兼ねて一応rebootするようにしています。

ssh nekop@s37.example.com
ssh-keygen
ssh-copy-id s37.example.com
vi /etc/ansible/hosts
ansible-playbook -vvvv /usr/share/ansible/openshift-ansible/playbooks/byo/config.yml | tee -a openshift-install-$(date +%Y%m%d%H%M%S).log
reboot

マルチノードの場合はglusterも一緒にセットアップできるのでglusterでPVを使えるようにするのがラクなんですが、シングルノードなのでhostPathでPVを作成しておきます。SELinuxでコンテナからのアクセスを許可するのにchconでsvirt_sandbox_file_tを設定します。

COUNT=100

sudo mkdir -p /var/lib/origin/openshift.local.pv/
for i in $(seq 1 $COUNT); do
    PVNAME=pv$(printf %04d $i)
    sudo mkdir -p /var/lib/origin/openshift.local.pv/$PVNAME
    cat <<EOF | oc create -f -
apiVersion: v1
kind: PersistentVolume
metadata:
  name: $PVNAME
spec:
  accessModes:
  - ReadWriteOnce
  - ReadWriteMany
  - ReadOnlyMany
  capacity:
    storage: 100Gi
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /var/lib/origin/openshift.local.pv/$PVNAME
EOF
done
sudo chcon -R -t svirt_sandbox_file_t /var/lib/origin/openshift.local.pv/
sudo chmod -R 777 /var/lib/origin/openshift.local.pv/

Reference

Red Hat OpenShift Application Runtimes

OpenShift 全部俺 Advent Calendar 2017

Red Hat OpenShift Application Runtimesがリリースされたのでさわってみたいと思います。Spring BootVert.x, WildFly Swarmなどを使ってOpenShift上でマイクロサービスアプリケーションの開発をサポートする製品です。

https://launch.openshift.io/ というサイトでプロジェクトのひな型が作成できるので、まずはそれを利用してWildFly Swarmのプロジェクトを見てみましょう。

f:id:nekop:20171206122227p:plain

生成されたプロジェクトはローカル開発とOpenShiftを利用した開発の両方に対応するfabric8を活用したプロジェクトのようです。oc get allを見てみると、Binaryビルドなので、ソースからOpenShift側でビルドされるのではなく、ローカルでビルドしたwarファイルを転送してコンテナイメージをビルドしている構成です。

$ mvn clean fabric8:deploy
(長いので省略)
$ oc get all
NAME                                          TYPE      FROM      LATEST
buildconfigs/booster-crud-wildfly-swarm-s2i   Source    Binary    1

NAME                                      TYPE      FROM      STATUS     STARTED         DURATION
builds/booster-crud-wildfly-swarm-s2i-1   Source    Binary    Complete   2 minutes ago   2m3s

NAME                                      DOCKER REPO                                             TAGS      UPDATED
imagestreams/booster-crud-wildfly-swarm   172.30.1.1:5000/test-rhoar/booster-crud-wildfly-swarm   latest    50 seconds ago

NAME                                           REVISION   DESIRED   CURRENT   TRIGGERED BY
deploymentconfigs/booster-crud-wildfly-swarm   1          1         1         config,image(booster-crud-wildfly-swarm:latest)

NAME                                HOST/PORT                                                     PATH      SERVICES                     PORT      TERMINATION   WILDCARD
routes/booster-crud-wildfly-swarm   booster-crud-wildfly-swarm-test-rhoar.192.168.42.143.nip.io             booster-crud-wildfly-swarm   8080                    None

NAME                                        READY     STATUS      RESTARTS   AGE
po/booster-crud-wildfly-swarm-1-deploy      1/1       Running     0          18s
po/booster-crud-wildfly-swarm-1-fgdj8       0/1       Running     0          15s
po/booster-crud-wildfly-swarm-s2i-1-build   0/1       Completed   0          2m

NAME                              DESIRED   CURRENT   READY     AGE
rc/booster-crud-wildfly-swarm-1   1         1         0         18s

NAME                             CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
svc/booster-crud-wildfly-swarm   172.30.79.11   <none>        8080/TCP   20s

BuildConfigを見ると利用イメージがregistry.access.redhat.com/redhat-openjdk-18/openjdk18-openshiftになっているので、これを使えば手元でビルドしてバイナリ転送ではなく、OpenShift側でソースからビルド(s2iビルド)でも大丈夫でしょう。

というわけでRHOARを利用した最小のSwarmプロジェクト https://github.com/nekop/hello-swarm を作ってみました。

$ oc new-project test-swarm
$ oc new-app registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift~https://github.com/nekop/hello-swarm
$ oc expose svc hello-swarm
$ curl hello-swarm-test-rhoar.192.168.42.143.nip.io
hello world