エフェメラルコンテナでJDKのデバッグツールを使う夢を見つつ、Podとコンテナのライフサイクルに思いを馳せる
気づいたらだいぶブログをサボっていました…。
これはKubernetesアドベントカレンダーの19日目のエントリーです。メリー・クリスマス!
エフェメラルコンテナ x JVMのデバッグツールという、誰得な話を書きたいと思います。
1 . エフェメラルコンテナとは
エフェメラルコンテナってなに?という解説は、@superbrothersさんが公開してくださっている以下の資料を見るのが一番ですので、ここでは簡単な説明に留めます。
- Qiita: Kubernetes 1.16: Ephemeral Containers (alpha)
- SpeakerDeck: Kubernetes 1.16 アルファ機能を先取り! エフェメラルコンテナ
エフェメラルコンテナは、実行中のPodにエフェメラルな(揮発的な、一時的な)コンテナを後から追加する機能です。 一般的には、コンテナには、動かしたいアプリケーションが必要としないコマンドやモジュールは極力含めないようにするのが良いとされています。 エフェメラルコンテナがあると、デバッグのためのコマンド等をそちらに入れて実行できるようになります。このため、アプリケーションのコンテナからデバッグのためだけに必要なコマンドやモジュールを排除することができ、理想的なコンテナが作成できるというわけです。
2 . エフェメラルコンテナからJDKのデバッグツールを使ってみる
ここから本題ですが、Java, Scala, Kotolinなど、JVMベースのアプリケーションをKubernetesで動かすことを考えてみます。 代用的なJDKディストリビューションのひとつであるOpenJDKには、jps, jmcd, jstack, jfrといった、JVMアプリのデバッグやトラブルシューティングのための便利なツール群が同梱されています。1
しかし、これらは JDK(Java Development Kit) の一部であって、アプリケーションの実行に必要なランタイムにあたる(Java Runtime Environment)には含まれません。アプリケーションを実行するコンテナには当然JREだけを入れおきたいわけですが、そうしてしまうと上記のツール群は利用できないということです。
ここでエフェメラルコンテナの登場ということになります。JVMアプリのコンテナ(JREを使って動いている)を含むPodに対して、JDKのエフェメラルコンテナを追加して、JDKに同梱されているデバッグツールを使っていこうというわけです。
それではやってみましょう…!
エフェメラルコンテナを利用可能なクラスターの作成
(!!!注意: ここから手順は期待通りに動かなかったというオチなので参考程度に御覧ください!!!)
@superbrothersさんの記事ではminikubeを使っていますが、せっかくなので最近覚えたkindを使ってクラスターを作っていきたいと思います。
エフェメラルコンテナは、最新のKubernetes 1.16から追加されたAlphaの機能です。このため、該当するバージョンで、かつ EphemeralContainers
というfeature gateを有効にする必要があります。
kindではクラスターの構成をyaml形式の設定ファイルで定義することができ、ここでfeature gateを指定することが可能です。
kind: Cluster apiVersion: kind.sigs.k8s.io/v1alpha3 kubeadmConfigPatches: - | apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration metadata: name: config apiServer: extraArgs: "feature-gates": "EphemeralContainers=true" scheduler: extraArgs: "feature-gates": "EphemeralContainers=true" controllerManager: extraArgs: "feature-gates": "EphemeralContainers=true" - | apiVersion: kubeadm.k8s.io/v1beta2 kind: InitConfiguration metadata: name: config nodeRegistration: kubeletExtraArgs: "feature-gates": "EphemeralContainers=true" nodes: - role: control-plane - role: worker
このようなファイルを作成したら、kindでクラスターの作成を行います。
kind create cluster --config kind-config.yaml
Creating cluster "kind" ...
✓ Ensuring node image (kindest/node:v1.16.3) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
… (snip) …
クラスターが出来上がったら、feature gateが有効になっていることを確認してみます。
$ kubectl get po -n kube-system kube-apiserver-kind-control-plane -o yaml | grep feature-gates
- --feature-gates=EphemeralContainers=true
これでクラスターは準備OKです。
kubectl-debugプラグインのインストール
kubectlでエフェメラルコンテナを追加するには、 kubectl debug
サブコマンドが必要ですが、これを利用にするために、kubectl-debugプラグインを導入します。
(linux_amd64環境での実行例です。環境に合わせて読み替えをお願いします)
$ cd $(mktemp -d)
$ curl -LO https://github.com/verb/kubectl-debug/releases/download/v0.1.2/kubectl-debug_linux_amd64.tar.gz
$ tar xvzf kubectl-debug_linux_amd64.tar.gz
$ sudo mv kubectl-debug /usr/local/bin/
$ kubectl debug -h
JVMアプリのPodを動かす
サンプルのJVMアプリのPodを動かしておきます。
この記事のケースではOpenJDKのJREで動いているアプリであればなんでもOKです。例えば、以下のようなmanifestを作ります。
apiVersion: v1 kind: Pod metadata: name: cowweb spec: shareProcessNamespace: true containers: - name: cowweb image: registry.hub.docker.com/hhayakaw/cowweb:v2.1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 8080
shareProcessNamespace: true
となっているところが大切なポイントの1つで、これによってPod内のコンテナがプロセス空間を共有することができます。つまり ps
コマンドなどで、Pod内の他のコンテナで動いているプロセスが見えることになります。
それではこのmanifestをクラスターに適用します。
$ kubectl apply -f cowweb.yaml $ kubectl get pod $ NAME READY STATUS RESTARTS AGE $ cowweb 1/1 Running 0 9s
Podにエフェメラルコンテナを追加する
それでは、エフェメラルコンテナとしてJDKのコンテナをPodに追加します…。と言いたいところなのですが、公式のOpenJDKのイメージはENTRYPOINTがjShellというツールになっていて、通常のシェルではありません。 今回のような使い方では通常のシェルからデバッグツールを実行したいので、以下のようなENTRYPOINTだけを書き換えたコンテナを作って、あらかじめレジストリにPushしておく必要がありました。
FROM openjdk:11-jdk-slim ENTRYPOINT ["/bin/sh"]
それではいよいよ、Podにエフェメラルコンテナを追加します。 -m
は追加するエフェメラルコンテナのイメージ名(この前の手順でPushしたものを指定)、 -c
はコンテナの name
を指定するオプションです。
kubectl debug cowweb -m hhayakaw/jdk11-debug -c jdebug
Podの内容を見てみると、エフェメラルコンテナが追加されていることがわかります。
kubectl describe pod cowweb | grep -A 5 Ephemeral
このエフェメラルコンテナに kubectl attach
します。
kubectl attach -it cowweb -c jdebug
これでエフェメラルコンテナ(OpenJDK 11が入っている)のシェルプロンプトにアクセスできました。
デバッグツールを使う…!(うまく行かない)
いよいよ、デバッグツールを使うときが来ました。
Podには shareProcessNamespace: true
がつけてあるので jps
を打てばアプリのJVMのプロセスが見えるはず。手始めに jps
からの jcmd
でJVMの起動フラグの一覧でも見てみるか、と思うわけですが…。
# jps
29 Jps
jpsそのもののプロセスしか見えない…?あれー、なんで?
...
調べてみたところ、jpsを利用するには ptrace
システムコールが必要になるようで、エフェメラルコンテナにこれを実行できる権限をつけないといけません。しかし、 kubectl debug
コマンドにはそんな権限を追加するオプションはない…。
仕方ないので、JSONで securityContext
で SYS_PTRACE
が有効になるように記述したエフェメラルコンテナを作って、 kubectl replace
でPodに追加してみます。 kubectl replace
でエフェメラルコンテナを追加する方法は、公式ドキュメントにサンプルがあったので、それに securityContext
の記述を追加してあげる感じです。
まずはJSON。
{ "apiVersion": "v1", "kind": "EphemeralContainers", "metadata": { "name": "cowweb" }, "ephemeralContainers": [ { "name": "jdebug", "image": "openjdk:11-jdk-slim", "imagePullPolicy": "IfNotPresent", "command": [ "/bin/sh" ], "stdin": true, "tty": true, "terminationMessagePolicy": "File", "securityContext": { "capabilities": { "add": [ "SYS_PTRACE" ] } } } ] }
エフェメラルコンテナ追加!
kubectl replace --raw /api/v1/namespaces/default/pods/cowweb/ephemeralcontainers -f jdebug.yaml
え…。
The Pod "cowweb" is invalid: spec.ephemeralContainers[0].securityContext: Forbidden: cannot be set for an Ephemeral Container
securityContext: Forbidden
。どうやらエフェメラルコンテナではやろうとしている権限追加は制限されているようです。
残念ながら、JVMのデバッグツールは、エフェメラルコンテナからでは使えないという結論に…。
3 . KubernetesでJDKのデバッグツールを利用する現状可能な方法
ということで、似たようなことを現状のKubernetesの機能でやろうとするとどうなるかというと、エフェメラルコンテナの代わりにサイドカーコンテナを使うことが考えられます。
つまり、下のように、JDK入りのコンテナをあらかじめPodに入れておくというやり方です。
apiVersion: v1 kind: Pod metadata: name: cowweb spec: shareProcessNamespace: true containers: - name: cowweb image: registry.hub.docker.com/hhayakaw/cowweb:v2.1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 8080 - name: jdebug image: openjdk:11-jdk-slim imagePullPolicy: IfNotPresent command: ['/bin/sh'] stdin: true tty: true terminationMessagePolicy: File securityContext: capabilities: add: - SYS_PTRACE
このようなPodを作った上でサイドカーコンテナ(jdebug)にアタッチすれば、JVMツールを利用することが可能です。
kubectl attach -it cowweb -c jdebug
以下のように、 jps
でJVMアプリのプロセスIDを確認して、 jcmd
でJVMのフラグを表示する、といったことができます。
# jps 7 cowweb.jar <-- アプリのプロセスが見えている 29 Jps # jcmd 7 VM.flags 7: -XX:CICompilerCount=2 -XX:InitialHeapSize=264241152 -XX:MaxHeapSize=4204789760 -XX:MaxNewSize=1401552896 -XX:MinHeapDeltaBytes=196608 -XX:NewSize=88080384 -XX:NonNMethodCodeHeapSize=5825164 -XX:NonProfiledCodeHeapSize=122916538 -XX:OldSize=176160768 -XX:ProfiledCodeHeapSize=122916538 -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseSerialGC
しかし、サイドカーコンテナをデバッグのために使う場合、必要なときだけこのコンテナを起動するということはできません。 Kubernetes的には本体(ここではJVMアプリ)のコンテナもサイドカーコンテナも取り扱いに区別はなく、どちらかのコンテナが動作していないPodは異常な状態とみなされて、再起動がかけられてしまいます。
このため、JDKの入ったコンテナを、普段は使わないのに上げっぱなしにしておかなければいけないわけです。もちろん、コンテナが動いていると言ってもJVMまで起動しているわけではないので、リソース(メモリやCPU)の消費は大したことはありません。しかしPodの中に余計なものがあるのは好ましくありませんし、権限の強いコンテナが置きっぱなしなのはセキュリティ的にもいいことではないでしょう。
4 . まとめ - Podとコンテナのライフサイクルについて
サイドカーコンテナを使えばアプリのコンテナに対してJVMツールを実行することが可能ですが、本体のコンテナと起動・停止のライフサイクルが同じになるように強制されてしまうため、デバッグという用途だけを考えると理想的ではありません。エフェメラルコンテナは、Podに後から追加できるなど、デバッグに適した本体のコンテナとは別のライフサイクルを持っていますが、JVMのデバッグツールを実行するには制限がありました。
いまのところ、JVMのデバッグツールという限られた用途に関していうと、エフェメラルコンテナは機能が足りていないということになりそうです。
ただ、今回の検証は残念な結果に終わってしまったものの、エフェメラルコンテナの特徴である「本体のコンテナと別のライフサイクルを持つ追加コンテナ」というコンセプトには、大きな可能性を感じました。
例えば、1)アプリ本体のコンテナに対して、起動初期に暖機運転のトラフィックを送るだけのコンテナを設けたり、2)ログエージェントのような、それが死んでもPodを落とすまではしてほしくない、といったケースは現実に存在すると思います。これらをカバーするには、本体のコンテナとは独立したライフサイクルが求められてくると思うのです。
こういった機能が徐々にサポートされて、Kubernetesがより便利に発展していってくれるといいですね。自分もできる働きかけしていければと思います。
深夜3:00を回ってだいぶ取り留めがなくなってきたので、このへんで…。
皆さん良いお年をお迎えください。メリー・クリスマス!
-
他にも同じものを含むディストリビューションもあるかもしれません↩
Helidonで作ったマイクロサービスをPrometheus Operatorでサクッとモニタリング
Helidonとは
HelidonはマイクロサービスなWeb APIを実装することを想定したJavaのフレームワークです。以下のような特徴があります。
- 割と軽い実装で、パフォーマンスに優れる
- MicroProfileの実装の一つ
- PrometheusやZipkinの形式のメトリック/トレーシングの情報を簡単に取得できる
このエントリーでやること
Helidonで作ったマイクロサービスをPrometheus Operatorでサクッとモニタリングしてみます。だいたい以下のような流れになります。
- Kubernetesクラスター上に、PrometheusとPrometheus Operatorをデプロイする
- Helidonでアプリを作成し、Kubernetesクラスターにデプロイする
- Prometheusでアプリのアクセスカウンターをモニタリングする
では順に行きたいと思います。
1. Kubernetesクラスター上に、PrometheusとPrometheus Operatorをデプロイする
CRDやらなんやらをKubernetesクラスターに作ることになるので、kubectlコマンドを実行するアカウントに必要な権限をつけておきます。 今回はKubernetesの環境として、OKE(Oracle Container Engine for Kubernetes)を利用します。この場合、以下のようなコマンドを実行します(cluster-adminロールをつけて楽しちゃってます)。
kubectl create clusterrolebinding [Cluster Role Bindingオブジェクトの名前] --clusterrole=cluster-admin --user=[kubectlの実行アカウントのOCID]
詳細はOKEのドキュメントを参照ください。
次に、適当なディレクトリにPrometheus Operatorをcloneします。
git clone -b v0.28.0 https://github.com/coreos/prometheus-operator.git
cd prometheus-operator
諸々をクラスターにデプロイします。 (2019/02/06時点でkube-prometheusはExperimentalだそうなので、今後同じ方法が使えるかは未知数です)
kubectl apply -f contrib/kube-prometheus/manifests/
Podが上がりきったのを確認したら、Prometheusのダッシュボードにアクセスします。PrometheusにのダッシュボードにつながるServiceはClusterIPで作られているので、port forwardを使います。
kubectl --namespace monitoring port-forward svc/prometheus-k8s 9090
上のコマンドを実行したら、ブラウザでhttp://localhost:9090/にアクセスします。以下のような感じでダッシュボードが表示されればOKです。
2. Helidonでアプリを作成し、Kubernetesクラスターにデプロイする
HelidonのアプリはクイックスタートにあるHello World的なアプリを使います。
まず、以下のコマンドを実行します。
mvn archetype:generate -DinteractiveMode=false \ -DarchetypeGroupId=io.helidon.archetypes \ -DarchetypeArtifactId=helidon-quickstart-se \ -DarchetypeVersion=0.11.0 \ -DgroupId=io.helidon.examples \ -DartifactId=quickstart-se \ -Dpackage=io.helidon.examples.quickstart.se
cd quickstart-se
これでHelidonのプロジェクトの雛形が作成されますが、この雛形にはすでにHello World的なAPIが実装されています。
この雛形に、カスタムメトリックとしてアクセスカウンターを追加してみます。
やり方はHelidonのドキュメントのMetrics supportに従えばOKですが、quickstartを使っている場合、必要な手順は一箇所だけ、GreetingServiceにアクセスカウンターを書き足す作業です。
vim src/main/java/io/helidon/examples/quickstart/se/GreetService.java
以下、diff形式で差分を記します。行頭に +
が書かれているところを追記すればOKです。
@@ -25,6 +25,10 @@ import io.helidon.webserver.ServerResponse; import io.helidon.webserver.Service; +import io.helidon.metrics.RegistryFactory; +import org.eclipse.microprofile.metrics.Counter; +import org.eclipse.microprofile.metrics.MetricRegistry; + /** * A simple service to greet you. Examples: * @@ -42,6 +46,10 @@ public class GreetService implements Service { + private final MetricRegistry registry = RegistryFactory.getRegistryFactory().get() + .getRegistry(MetricRegistry.Type.APPLICATION); + private final Counter accessCtr = registry.counter("accessctr"); + /** * The config value for the key {@code greeting}. */ @@ -58,6 +66,7 @@ @Override public void update(Routing.Rules rules) { rules + .any(this::countAccess) .get("/", this::getDefaultMessageHandler) .get("/{name}", this::getMessageHandler) .put("/greeting/{greeting}", this::updateGreetingHandler); @@ -108,4 +117,9 @@ response.send(returnObject); } + private void countAccess(ServerRequest request, ServerResponse response) { + accessCtr.inc(); + request.next(); + } + }
Kubernetesにデプロイするためのmanifestファイルの雛形もあります。 後の手順でアプリをコンテナ化しますが、このときのイメージ名に合うように、manifestで指定するイメージ名を修正しておきます。
vim src/main/k8s/app.yaml
イメージ名をしている箇所で、元のイメージ名の頭に "[Docker Hubのアカウント名]/" を追記します。以下はhhiroshellというアカウント名の場合です。
@@ -43,7 +43,7 @@ spec: containers: - name: ${project.artifactId} - image: ${project.artifactId} + image: hhiroshell/${project.artifactId} imagePullPolicy: IfNotPresent ports: - containerPort: 8080
コードの編集が終わったら、アプリケーションをビルドしてローカルで実行してみます。まずはビルドから。
mvn package
[INFO] Scanning for projects... ...(中略)... [INFO] [INFO] --- maven-jar-plugin:2.5:jar (default-jar) @ quickstart-se --- [INFO] Building jar: /mnt/c/Users/hhiroshell/Development/devsumi/quickstart-se/target/quickstart-se.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 34.004 s [INFO] Finished at: 2019-02-06T14:14:55Z [INFO] ------------------------------------------------------------------------
上記の様に BUILD SUCCESS で終わっていればOKです。次に、アプリを起動します。
java -jar target/quickstart-se.jar
何回かgreetingのAPIにアクセスして、アクセスカウンターをカウントアップさせておきます。
curl http://localhost:8080/greet
Helidonは、Prometheusからメトリックを取得するためのEndpointをデフォルトで持っています。ですので、直接 /metrics/ というパスにアクセスするとメトリックを取得できます。新たにExporterを用意する必要はありません。
先程追加したアクセスカウンターは、application:accessctr という名前でメトリックを提供しています。エンドポイントにアクセスして、このアクセスカウンターの値を見てみます。
curl -s -H 'Accept: text/plain' -X GET http://localhost:8080/metrics/ | grep accessctr
# TYPE application:accessctr counter # HELP application:accessctr null application:accessctr 5
この様になれば、仕込んでおいたアクセスカウンターのメトリックが取得できていることになります。Prometheusの形式で値が返ってきていることが分かります。
それでは、このアプリをKubernetesにデプロイします。雛形からDockerfileやKubernetesのmanifestが生成済みなので、それを利用していきます。
まずはコンテナのビルド。
docker build -t [Docker Hubのアカウント名]/quickstart-se target
具体的には、例えばこのようなコマンドになります。
docker build -t hhiroshell/quickstart-se target
次にコンテナレジストリにプッシュ。Docker Hubを使っているので、ログインが求められたらDocker Hubのユーザー名とパスワードを入力してください。
docker push [Docker Hubのアカウント名]/quickstart-se
具体的には、例えばこのようなコマンドになります。
docker push hhiroshell/quickstart-se
続いて、kubernetesにデプロイします。
kubectl apply -f target/app.yaml
雛形から生成したmanifestだと、NodePortタイプのServiceが作られている状態です。クラスター上のアプリにアクセスするため、まずはNodeのIPアドレスと、Serviceが公開されているPort番号を確認します。
kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME 132.145.27.98 Ready node 2h v1.11.5 10.0.10.2 132.145.27.98 Oracle Linux Server 7.5 4.14.35-1818.2.1.el7uek.x86_64 docker://18.3.1
この結果から、EXTERNAL-IP の値を使います(Nodeが複数表示される場合どのNodeでもOK)。
次にPort番号です。
kubectl get service quickstart-se
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE quickstart-se NodePort 10.96.255.64 <none> 8080:31621/TCP 7m
PORT(S)の :
の右側にある値を使います。上の例では31621です。
それでは、Kubernetesクラスター上のアプリケーションにアクセスしてみます。
curl "http://[上で確認したIP]:[上で確認したPort番号]/greet"
何度かアクセスを繰り返して、アクセスカウンターの値を増やしておいてください。
これでHelidonのアプリのビルドとデプロイが完了しました。
3. Prometheusでアプリのアクセスカウンターをモニタリングする
Prometheus Operatorを使ってPrometheusを利用する場合、監視対象を追加するにはServiceMonitorというカスタムリソースを使います。これは、KubernetesのServiceがルーティング対象とするPodを、自動的にメトリック収集対象とするものです。
今回は、以下のようなカスタムリソースを、quickstart-service-monitor.yamlというファイル名で作成します。
apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: quickstart-service-monitor labels: app: quickstart-se spec: selector: matchLabels: app: quickstart-se endpoints: - port: http
このServiceMonitorは、Label Selectorとして app: quickstart-se
と指定しています。こうすると、同じlabelを持ったServiceがルーティング対象とするPodに対して、メトリックを取得しに行くするように設定されます。
多くの場合、Prometheusがメトリックを取得しに行くEndpointにはExporterを用意しますが、HelidonはこのEndpointを予め持っており、そこから直接メトリックを得ることができます。
ではこのSerivceMonitorをクラスターに適用します。
kubectl apply -f quickstart-service-monitor.yaml
Prometeusの設定はこれだけでOKです。Operator便利ですね。
では、ブラウザでhttp://localhost:9090/にアクセスして、Prometheusのダッシュボードを表示します。
port-forwardが切れていたら、以下を実行してから上記のURLにアクセスします。
kubectl --namespace monitoring port-forward svc/prometheus-k8s 9090
Expressionに"application:accessctr"と入力してExecuteをクリックすると、アクセスカウンターの値が取得できていることがわかります(メトリックが収集させるまでタイムラグがあるので、何も表示されなかった場合は少し時間を置いてください)。
次に、アプリをスケールアウトした場合も自動的に監視対象に追加されることを確認してみます。
まず、以下のコマンドでアプリのPod数を3に増やします。
kubectl scale deployment quickstart-se --replicas=3
アクセス数を追加でカウントアップさせるため、アプリへのアクセスを何度か行っておきます。
(↓を何度か実行)
curl "http://[上で確認したIP]:[上で確認したPort番号]/greet"
Prometheusのダッシュボードでアクセスカウンターのメトリックを観察すると、Pod毎に値が取得できていることがわかります。
まとめ
Helidonで作成したアプリのカスタムメトリックを、Prometheus Operatorを使ってモニタリングすることができました。
HelidonはExporterいらずでモニタリングできて便利です。また、Prometheus Operatorを使うとカスタムリソースを使うことで簡単にメトリックの収集対象を設定できます。
本エントリーは以上です!
Werckerのパイプライン内でDockerfileからコンテナをビルドする方法
Werckerはパイプラインの実行環境となっているコンテナからコンテナイメージを作るのがデフォルトの動きですが、なるべく軽量なコンテナにしたいなど、用途に最適化されたコンテナを作りたいという場合もあります。
そんなときは、コードリポジトリにDockerfileを入れておいて、それを使ってビルドすればOKです。
wercker.ymlの書き方は以下のような感じです。
box: alpine:3.6 build: steps: - internal/docker-build: name: build custom container. dockerfile: Dockerfile image-name: custom-container - internal/docker-push: name: push custom container. image-name: custom-container username: $REGISTRY_USERNAME password: $REGISTRY_PASSWORD repository: hhiroshell/custom-container tag: 1.0
internal/docker-build
で所望のDockerのコンテキストでコンテナをビルドできます。
dockerfile:
に設定しているのはDockerfileまでのパスです。パイプラインの実行中は、コードリポジトリのrootに当たるディレクトリがカレントになっています。上の例はコードリポジトリのrootの直下にDockerfileを置いておき、それを参照していることになります。
image-name:
は後続のStepでイメージを操作したいときに、イメージを特定するための名前です。この例だと docker-push
StepでビルドしたイメージをPushしています。
その他いろいろな設定が可能ですが、詳細は公式ドキュメントに詳しいです。
Oracle Cloud InfrastructureのCLIをvirtualenv環境内にインストールする
Oracle Cloud Infrastructure(以下、OCI)のCLIはPythonで実装されています。Pythonのvirtualenvを使って、OCI CLI専用の環境を切ってインストールしておけば、Pythonにありがちな依存モジュールの問題に悩まされずに済みますので、このエントリーではその手順を書きます。1
ちなみに、本エントリーとは直接関係ありませんが、CLIの他にOCIのAnsibleモジュールも使いたい場合には、より一層virtualenvの利用をおすすめしたいです。OCIのAnsibleモジュールはOCIのPython SDKというものに依存しているのですが、自分の環境では依存モジュールの問題にはまって動かすまで苦労したので…。
前提条件
こんな環境でやりました。
手順
pipをインストール
sudo apt update
sudo apt install python3-pip
pipでvirtualenvをインストール
pip3 install virtualenv
OCI CLI用のvirtualenv環境を作成。virtualenvは新たにディレクトリを切って、その配下で依存パッケージが管理される仕組みです。ここでは、~/.pyenv_oci-cli
という名前のディレクトリにしています。
python3 -m virtualenv ~/.pyenv_oci-cli --no-site-packages
上で作成したvirtualenvを有効化
source ~/.pyenv_oci-cli/bin/activate
pipでvirtualenv環境にOCI CLIをインストール
pip install oci-cli
動作確認。以下のコマンドでヘルプが表示されればOKです。
oci -h
新たにシェルを立ち上げたら、都度virtualenvの有効化を行う必要があります。頻繁にOCI CLIを使うのであれば、.bashrc
とか.zshrc
に該当コマンドを書いておくと良いかと思います。
source ~/.pyenv_oci-cli/bin/activate
OCI CLIのインストールはこれで完了です。CLIの環境設定の手順はvirtualenvを使っていてもいなくても同じなので、「Oracle Cloud Infrastructure CLIを設定してみた」などを参考にして実施してください。
Ubuntu 18.04 bionicにOpenJDK 11をインストールする
2018/12/27現在、Ubuntu 18.04でaptでOpenJDKをインストールするとjdk10がインストールされるようになっています。1
いろいろと対処法はあるようなのですが、せっかくなので本家のOpenJDKを落として手動でインストールしとこうということで、その手順を残しておきます。
手順
OpenJDKのダウンロードサイトに行って、ビルド済みのアーカイブを取得するためのURLを確認します。
Ubuntu 18.04の場合は、Linux/x64のURLを確認して適当に控えて置きます。
以下、順次以下のコマンドを実行します。URLやファイル名などは本稿執筆時点のものなので、作業を行う時点のものを確認して適宜置き換えてください。
アーカイブのダウンロード
wget https://downlo8ad.java.net/java/GA/jdk11/13/GPL/openjdk-11.0.1_linux-x64_bin.tar.gz -O ./openjdk-11.0.1_linux-x64_bin.tar.gz
解凍
sudo mkdir /usr/lib/jvm
sudo tar xfvz ./openjdk-11.0.1_linux-x64_bin.tar.gz --directory /usr/lib/jvm
お掃除
rm openjdk-11.0.1_linux-x64_bin.tar.gz
コマンドにシンボリックリンクを貼っておく
java
とjavac
くらいはやっておくと便利かと。
sudo ln -s /usr/lib/jvm/jdk-11.0.1/bin/java /usr/bin/java
sudo ln -s /usr/lib/jvm/jdk-11.0.1/bin/javac /usr/bin/javac
動作確認
こんな結果になればおk
java -version
openjdk version "11.0.1" 2018-10-16 OpenJDK Runtime Environment 18.9 (build 11.0.1+13) OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)
以上です。
OKE、OCIRを使うときに権限制御するための設定まとめ
このエントリーはOracle Cloud アドベントカレンダーその2の22日目です。
今回はOracleが提供するコンテナ関連のクラウドサービスである、OKE、OCIRを使う上での、準備に当たる作業の話を書きたいと思います。
- OKE:
- Oracle Container Engine for Kubernetes
- Oracleが提供するマネージドKubernetesサービス
- OCIR
これらを使うには、Policyと呼ばれるアクセス権限の設定を予めしておく必要があります。 このエントリーでは、それら必要な権限周りの設定を整理したいと思います(他のエントリーではそのエントリーで必要なものだけ書いているので)。
管理者権限を打ち込めばすぐに使えるようにはなりますが、ちゃんと権限を分けたいときにはこの情報を算用してください。
OKEを使うために必要なポリシー
注: in tenancy
をin compartment [コンパートメント名]
のようにすると、権限の及ぶ範囲をコンパート名に絞る事ができます。
OKEのPaaSに与える権限OKEを使つときは必須
- Statement:
Allow service OKE to manage all-resources in tenancy
- 説明:
- OKEのPaaSに権限を与えるための特殊なポリシー。OKEを使うときはこれを必ず作る。これがないと始まらない
- Statement:
OKEクラスターとNode Poolを操作する権限
OKEクラスターとNode Poolを操作する権限 + ネットワークの操作権限
- Statement:
Allow group [グループ名] to manage cluster-family in tenancy
Allow group [グループ名] to manage virtual-network-family in tenancy
- 説明:
- OKEをネットワークも含めて作ったり操作したいときに必要な権限。2つ目の方は下回りのネットワークを操作するためのもの
- OKE作成のダイアログで
quick cluster
を使うときにはこの権限が必要
- Statement:
OKEクラスターを参照する権限
- Statement:
Allow group [グループ名] to inspect clusters in tenancy
- 説明:
- OKEのクラスターを参照する権限
- Statement:
OKEクラスターのNode Poolを操作する権限
- Statement:
Allow group [グループ名] to use cluster-node-pools in tenancy
- 説明:
- 作成済みのOKEクラスターのNode Poolを追加、削除、アップデート(構成変更など)する権限
- Statement:
OKEクラスターへの操作の監査情報を参照する権限
- Statement:
Allow group [グループ名] to read cluster-work-requests in tenancy
- 説明:
- OKEクラスターへの操作の監査情報を参照する権限
- Statement:
OCIRを使うために必要なポリシー
以下は全てを網羅したものではありませんが、ほとんどのケースはこれらがあれば大丈夫かと思います。
リポジトリの閲覧権限
- Statement:
Allow group [グループ名] to inspect repos in tenancy
- 説明:
- OCIRのリポジトリの閲覧権限
- Statement:
イメージの取得権限(全てのリポジトリ)
- Statement:
Allow group [グループ名] to read repos in tenancy
- 説明:
- OCIRの全てのリポジトリのイメージをpullする権限
- Statement:
イメージの取得権限(リポジトリを限定)
イメージの登録権限(全てのリポジトリ)
- Statement:
Allow group [グループ名] to use repos in tenancy
- 説明:
- OCIRの全てのリポジトリにイメージをpushする権限
- Statement:
イメージの登録権限(リポジトリが存在しない場合に新たに作る権限も追加)
OCIRへのフルアクセス
- Statement:
Allow group [グループ名] to manage repos in tenancy
- 説明:
- テナント内のリポジトリに対する全権限
- Statement:
Oracle Container Engine for KubernetesでLoadBlancerタイプのServiceを使う
このエントリーはOracle Cloud アドベントカレンダーその2の21日目です。
今回は、OKE(Oracle Container Engine for Kubernetes)で作ったKubernetesクラスターでLoadBalancerタイプのServiceを使う手順を紹介します。
0. 前提条件
1. 手順
ほとんどのマネージドKubernetesサービスは、自身のクラウド環境で提供されているロードバランサーのサービスと連携してServiceオブジェクトを作成する機能を提供しており、OKEも同様です。
1.1. まずはデフォルト設定で
まずは、my-nginx.yamlというファイル名で以下のような内容のファイルを作成します。
apiVersion: v1 kind: Service metadata: name: my-nginx-svc labels: app: nginx spec: type: LoadBalancer ports: - port: 80 selector: app: nginx --- apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80
これはなんの変哲もない、nginxのコンテナを公開するだけのmanifestファイルです。
これをOKEクラスターに適用してみます。
kubectl apply -f my-nginx.yaml
10-20秒程度おいてから以下のコマンドを実行し、Serviceオブジェクトの内容を確認してみます。
k get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 15m my-nginx-svc LoadBalancer 10.96.122.251 129.213.78.183 80:32250/TCP 30s
my-nginx-svcというServiceが129.213.78.183というIPアドレスで公開されていることがわかります(IPアドレスは環境や実行の度に変わります)。
ブラウザでこのアドレスhttp://129.213.78.183/
アクセスすると、OKEクラスターで動いているnginxからの応答を得ることができます。
Oracle Cloud Infrastructureのコンソールでロードバランサーの方を確認してみると、ランダムに生成されたと思しき名前でロードバランサーが作られていることがわかります。
IPアドレスは先程のアドレス一致します。また、シェイプは[100]Mbpsになっていると思います。
Oracle Cloud Infrastructureでは400[Mbps]と8000[Mbps]も提供しています。これらを使いたい場合には、Serviceオブジェクトの記述にannotationを追加します。
- 400[Mbps]
apiVersion: v1 kind: Service metadata: name: my-nginx-svc labels: app: nginx annotations: <--ココ service.beta.kubernetes.io/oci-load-balancer-shape: 400Mbps <--ココ ...(以下略)...
- 8000[Mbps]
apiVersion: v1 kind: Service metadata: name: my-nginx-svc labels: app: nginx annotations: <--ココ service.beta.kubernetes.io/oci-load-balancer-shape: 8000Mbps <--ココ ...(以下略)...
例えば400[Mbpx]でやってみます。ファイルを変更後、以下のコマンドを実行します。
kubectl delete -f my-nginx.yaml
kubectl create -f my-nginx.yaml
今度は400[Mbps]のロードバランサーができました!(ロードバランサーの作り直しになるので、IPアドレスも変わっています)
本エントリーでご紹介する内容は以上です。
シェイプを変更する以外にもSSLを終端するように設定したりすることも可能です。詳しくは公式のドキュメントを参照してください。