Create a gist now

Instantly share code, notes, and snippets.

Embed
cf ssh コマンドについて

cf ssh コマンドについて

この記事は、Cloud Foundry Advent Calendar 2017の10日目の記事です。

アプリケーションコンテナの中にSSHしたいだと?

Cloud Foundryがユーザとして想定している人たちって、どういう人達なのでしょう。

それはやっぱり、このAdvent Calender1日目で @jacopen さんがKubernetesとの使い分けの中で言及していたように、あくまでも アプリケーション開発をしており、それの運用を楽にしたいということでプラットフォームを選ぶ ような人なのです。 そういう人って、以下のような考え方が強いんじゃないですかね。

  1. アプリケーションの動作環境とかプロセスやディレクトリの構成などに、あまり興味はない。どういうしくみであろうと、私が書いたこのアプリケーションが cf push コマンド一発で問題なく動いてくれれば、それでいいから。
  2. アプリケーションを動作させた結果として出力されるログのありかや、ログの管理の方法などに興味はない。私が書いたこのアプリケーションが吐くログを簡単に見る方法を教えてくれれば、その通りにやるから。

Cloud Foundryコミュニティにおいてはそういう忖度を経て(未確認)、アプリケーションコンテナの中へSSHとかで接続してコマンドラインをとれるような機能追加開発の優先度を下げていたフシがあります(これは本当っぽい)。

上記1.に対しては「とにかくbuildpackを信ぜよ」という対応、上記2.に対しては「とにかくログはファイルじゃなくてSTDOUT/STDERRに出すようにアプリ書けよ。あとはプラットフォーム側でよろしくやってやるから」という対応ですね。

しかし、Cloud Foundryの普及をすすめる中で、アプリケーションコンテナの中にSSHしたいというご要望の声がやはり強かったのでしょう、tmateというしくみを使ってうまいことやっちゃう人も出てきました

人はなぜ、アプリケーションコンテナの中にSSHしたい、なんて思うのでしょうか。

  • 「とにかくbuildpackを信ぜよ」って言われても、コンテナ内のプロセスやディレクトリの構造とかを確認できないと、自分が書いたアプリが本当にちゃんと動いているのか確証が得られない
  • アプリサーバのローカルにログファイルを書き出しちゃうような昔ながらのアプリを持ち込んで動かそうとしているので、コンテナ内でコマンドプロンプトとったり、コンテナ内のファイルを取り出したりできないと、ログが見れなくて困る

そんなこんなで、Cloud Foundryコミュニティとしては、重い腰を上げざるを得なくなりました。

cf ssh コマンドの使い方

このへんを見てください。英語ですけど。

http://docs.cloudfoundry.org/devguide/deploy-apps/ssh-apps.html

・・・あ、はい、日本語で解説しますね。

基本的な使い方はカンタンです。

$ cf ssh [アプリ名]

これだけ。

アプリケーションを複数インスタンスで動かしている場合は、コンテナも複数ありますのでアプリ名だけの指定ではSSHするには足りませんが、

$ cf ssh [アプリ名] -i [index番号]

とやれば、どのコンテナにSSHするかを選ぶこともできるようになってます。

なお、SSHでログインできてしまうと、プロセスをkillしたりだのファイルを操作したりだのが思いのままなので、例えばproductionで動かしてるような場合だとこわいですよね。特定のアプリケーションでやたらとSSHできないようにするため、 cf disable-ssh cf enable-ssh とか、 cf disallow-space-ssh cf allow-space-ssh とかのコマンドもちゃんと用意されています。

あと、 cf ssh を使わず ssh コマンドを直接使いたい場合や、アプリケーションコンテナ内のファイルの操作を scpsftp でやりたい場合の手順もちゃんとあります

cf ssh-code という、SSHログイン用パスワード取得コマンドがあり、これを使って

$ ssh -p 2222 cf:[アプリUUID]/[index番号]@ssh.MY-DOMAIN.com

で取得したパスワード投入したら cf ssh と全く同じようなSSH接続ができる、と。なるほど。鍵認証ではなくパスワード認証なのが少しキモいですが、ログインIDもパスワードもプラットフォームが払い出したランダム値なので、まあ安心していいのかな。。。

どうやって実現しているのか

Cloud Foundryコミュニティにおいて、実装をためらうくらい難しいことになっています。

が、ドキュメントの方は比較的あっさりとしたものです。

あとは、このへんですかね。

・・・はいそうですね、これらだけで全貌を理解せよというのは厳しいものがありますので、こちらも日本語で解説しますね。

ひとまず、簡単な絵を描いてみました。

簡単な絵

思えば、私が生まれてこの方描いてきた絵の7割以上は、こういうアーキテクチャ説明系のやつのような気がするなあ・・・

・・・それはさておき、全体的な動きの流れを説明していきます。

アプリケーションを cf push してからコンテナ内でSSHサーバが起動するまでの部分

上記の絵の中では、青い矢印と黒い矢印で描いた部分になります。

CF CLIにて cf push すると、その裏でいくつかのCF APIが叩かれアプリケーションがCF上に登録されますが、その際には「このアプリケーションはコンテナ内でSSHサーバも動かすやつかどうか」の情報も登録されます。登録された情報の格納先は、cloud_controller_ng というコンポーネントが管理するいわゆるCCDBというデータベースです。

CCDBに登録されたアプリケーションを検知し、「よし、こいつを動かしてやろう」と決心する役割を持つのが nsync というコンポーネントです。 nsync はCCDBに登録された情報に基づいて、コンテナを作成後にコンテナ内で起動するコマンドを含むアプリケーションの起動条件をrecipeとして作成し bbs に投入する、という動きをします。ここで、「このアプリケーションはコンテナ内でSSHサーバも動かすやつかどうか」によって作成するrecipeの内容を変えています。具体的には、buildpackを使うアプリの場合はこのへん、Dockerイメージを使うアプリの場合はこのへんですね。生成されるrecipeは、具体的にはこのようなものになるようです。 なお、コンテナ内で起動するSSHサーバは diego-sshd という謎の名前になってますが、これはおなじみのOpenSSHサーバではなく、Cloud Foundryコミュニティ謹製の独自SSHサーバとなっています。少しでも使いにくかったら何でも独自に作っちゃうなあCF界隈は。

nsync から bbs に投入されたSSHサーバ起動指示入りのrecipeは、Diegoアーキテクチャのお家芸であるオークション形式のスケジューリングを経て、アプリケーションコンテナ置き場であるcell VM内での管理プロセスである rep によって解釈され、アプリケーションコンテナ内で diego-sshd が起動されます。 なお、アプリケーションコンテナの起動が成功すると、 bbs に対して「このVMのこのポート番号で接続を待ち受けているSSHサーバが起動しているよ」という情報が登録されます。

cf ssh してからSSHで接続が確立するまでの部分

上記の絵の中では、緑の矢印と紫の矢印で描いた部分になります。

Cloud Foundryで構築したプラットフォームにおいて、cell VMは通常複数デプロイされます。また、ひとつのcell VM上には通常複数のアプリケーションコンテナが配置されます。このため、アプリケーション毎(かつ、複数インスタンスの場合はインスタンス毎)に、SSH接続を待ち受けるIPアドレスとポート番号はまちまちになります。 どのアプリケーションのどのインスタンスがどのIPアドレスとポート番号でSSH接続を待ち受けているかの情報は、上述の通り bbs によって保持されています。これを使ってアプリケーションコンテナへのSSH接続を振り分けるのが ssh-proxy というコンポーネントです。 ssh-proxy は複数稼働させる冗長構成が可能となっており、その場合はLayer 4ロードバランサを配置することになります。

ssh-proxy には、Cloud Foundryにおける認証機能を担うUAAと連携し、SSH接続の認証に用いるパスワードを取得する機能も具備しています。 CF CLIもこの機能を具備しているので、パスワード認証でのSSH接続ができるわけです。

お分かりになりましたかね? いや、これでもまだ説明が不十分かもしれないですねえ。。。

めでたしめでたし。おしまい。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment