Movatterモバイル変換


[0]ホーム

URL:


29,545 views

Kubernetesにまつわるエトセトラ(主に苦労話)

Dockerをちゃんと使おうと考えていたらKubernetesに出会いました。ERPのシステム開発でkubernetesを使おうとして苦労した、あるいは現在進行形で苦労していることを、そもそもKubernetesが解決しようとしている課題やそのアーキテクチャそのものにも言及しながらお話します。Dockerをベースにシステム設計を行おうとしている方にノウハウ(主に苦労話)を共有します。July 24th, 2016 July Tech Festa 2016

Embed presentation

2 0 1 6 年 7 月 2 4 日 井 上 誠 一 郎Demystifying Kubernetes
自己紹介: 井上誠一郎• 元アリエルネットワークCTO (先月まで)• ワークスアプリケーションズ エグゼクティブフェロー• 主な著書• 「P2P教科書」• 「パーフェクトJava」• 「パーフェクトJavaScript」• 「実践JS サーバサイドJavaScript入門」• 「パーフェクトJava EE」(来月出版)
今日のセッションの目的•複雑怪奇なKubernetesをひもといていきます•Kubernetesのバージョンはv1.2.6ベースで説明します
複雑さをひもとくための工夫•Kubernetes固有の概念/用語がたくさんあるので、説明のために簡易化していきます•概念を下から積み上げていきます
Kubernetes理解に必要な知識(私見)Dockerの理解Dockerのネットワークの理解flanneldの理解コンテナとpodの関係の理解podとサービスの関係の理解Kubernetesのネットワークの理解(DNSとルーティング)Kubernetesのツールの理解この順序で説明
コンテナに関しての簡易化• 理屈で言えばコンテナはひとつのOS相当なので、ひとつのコンテナ内で多数のプロセス、たとえばロードバランサ、アプリケーションサーバ、データベースすべてを動かせます• しかし、Kubernetesの思想的には、ひとつのコンテナで動くプロセスの数を最小限にして、代わりに、コンテナ群を管理します• 今回の説明上も、ひとつのコンテナ上で動くのはひとつのプロセス、というモデルを前提にします(Kubernetesの必須要件ではありませんが)
Kubernetesの動作の分解の前に•そもそもKubernetesは何をしてくれるのか?•Kubernetesを使うと何がうれしいのか?
Kubernetesがやってくれること• 複数ホストにコンテナをデプロイ• コンテナ間のネットワーク管理(名前解決含む)• コンテナの死活監視• コンテナの負荷分散• コンテナのリソースアロケーション
• 複数ホストにコンテナをデプロイ• どのホストにどのコンテナ(=プロセス)を配備するかを隠蔽• コンテナ間のネットワーク管理(名前解決含む)• サービスディスカバリ相当の機能• コンテナの死活監視• コンテナ(=プロセス)が死んだら、コンテナを自動で新規起動• コンテナの負荷分散• 同一機能の複数コンテナ(=プロセス)へのアクセスをバランシングする機能(あまりリッチではない)• コンテナのリソースアロケーション• コンテナごとにCPUリソースやメモリリソースの割り当てを指定できる機能(あまりリッチではない)Kubernetesがやってくれること
Kubernetesがない世界プロセスA プロセスB依存実行環境開発者プロセスBプロセスBプロセスBプロセスBdeployLBプロセスALBプロセスAconfiguration(個々のエンドポイントを設定)
Kubernetesがある世界プロセスA プロセスB依存実行環境開発者プロセスBプロセスBプロセスBLBプロセスAKubernetesプロセスB群のサービス名を定義プロセスAにサービス名を与える
用語と概念の整理
• Dockerプロセスが動いているOSをホスト(マシン)と呼びます• ひとつのホストの上で、コンテナが複数稼働します• Kubernetesの世界から見ると、ホストマシンが物理マシンか仮想マシンかはどうでもいい話です。気にしないでください• 同様に、ホストマシンがネットワークのどこにいるか(プライベートネットワーク or グローバルIPを持つ)もKubernetesの世界からはスコープ外なので、気にしなくて結構ですホストマシンについて
• Kubernetesで最初に混乱するのが、Dockerのネットワークまわりです• flanneldの世界とKubernetesの話が混ざると混乱するので、話を分離します• まずflanneldだけに話を限定しますDockerのネットワークまわりの話とflanneld
• flanneldがないと、あるホストの上で動いているコンテナは、他のホストの上で動いているコンテナのIPアドレスにアクセスできません• 正確に言えば、ある設定をすれば、相手側ホストのIPアドレス経由で、リモートのコンテナにアクセスできます• ただ、基本的には少々面倒な世界ですflanneldの役割(1)
• flanneldは各ホスト上で動くデーモンプロセスです。flanneldがいれば、ホスト群の上のコンテナ群はコンテナ自身のIPアドレスを使って相互にアクセスできます• コンテナたちは一意なIPアドレスを持つようになります• 一見すると、ホスト間のコーディネーションが必要そうですが、仕組みはもっと単純で、flanneldプロセス群が同じデータストア(etcd)でルーティングテーブルを共有しているだけです• なお、この領域には、Docker Swarmなど類似機能の他技術も存在しますflanneldの役割(2)
1. (そもそもDockerのネットワーク補助のためなので)Docker自身をインストール2. 共有データストアとしてetcdが必要なので、どこかにetcdを起動(etcd自体は分散KVSですが、動作確認だけであれば、単体でどこかで起動していれば充分)3. etcdにflanneldが使うネットワークアドレスを登録(どのネットワークアドレスを使うかは利用者の自由)例$ etcdctl set /coreos.com/network/config'{ "Network": "10.1.0.0/16" }‘flanneldを動かす手順の概要(1)
4. 各ホストでflanneldデーモンプロセスを起動例同一ホストでetcdが動いている場合は単に$ sudo bin/flanneld別ホスト(IPアドレスが10.140.0.14)でetcdが動いている場合は$ sudo bin/flanneld -etcd-endpoints'http://10.140.0.14:4001,http://10.140.0.14:2379'flanneldを動かす手順の概要(2)
5. 個々のflanneldは、どのサブネットを確保したかの情報を/run/flannel/subnet.env に書き出す例$ cat /run/flannel/subnet.envFLANNEL_NETWORK=10.1.0.0/16FLANNEL_SUBNET=10.1.19.1/24FLANNEL_MTU=1432FLANNEL_IPMASQ=true6. dockerプロセスに対して、上記のサブネットを使うように指示して起動$ source /run/flannel/subnet.env$ sudo docker -d --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}flanneldを動かす手順の概要(3)
ifconfigでdocker0やflanneldのネットワークアドレスを確認(出力例は抜粋)(下記例の場合、このホスト上のコンテナ群は 10.1.19.0/24 のネットワークを構成)$ ifconfigdocker0 Link encap:Ethernet HWaddr 02:42:a5:18:b3:73inet addr:10.1.19.1 Bcast:0.0.0.0Mask:255.255.255.0flannel0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00inet addr:10.1.19.0 P-t-P:10.1.19.0Mask:255.255.0.0flanneldの動作確認(1)
ルーティングテーブルの確認:$ netstat -rnKernel IP routing tableDestination Gateway Genmask Flags MSS Window irttIface0.0.0.0 10.140.0.1 0.0.0.0 UG 0 0 0ens410.1.0.0 0.0.0.0 255.255.0.0 U 0 0 0flannel010.1.19.0 0.0.0.0 255.255.255.0 U 0 0 0docker010.140.0.1 0.0.0.0 255.255.255.255 UH 0 0 0ens4他のホスト上のコンテナのIPアドレス(たとえば10.1.79.2)に向けて接続できればOKflanneldの動作確認(2)
• なかなか面倒...• まず、dockerのデーモンプロセス起動より先にflanneldプロセスの起動が必要• かつ、flanneldプロセス起動時に、etcdの固定アドレスを外から与える必要がある• 更に、flanneldの書き出した /run/flannel/subnet.envの結果を、dockerのデーモンプロセスの起動時に渡す必要があるOS起動時のflanneldの自動起動(1)
systemdであれば$ sudo vi /lib/systemd/system/docker.serviceでEnvironmentFile=-/run/flannel/subnet.envを追記(先頭のハイフンの意味は、ファイルが存在しなければ無視する、というオプション)#下記に書き換え ExecStart=/usr/bin/docker daemon -Hfd:// $DOCKER_OPTSExecStart=/usr/bin/docker daemon -H fd:// $DOCKER_OPTS --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}OS起動時のflanneldの自動起動(2)
• Kubernetes理解のための、flanneldの最小理解• flanneldを使うと、Kubernetes管理下にいる各コンテナは一意なIPアドレスを持ち、相互にリーチャブルになる• flanneldネットワークは、プライベートネットワークなので、Kubernetesの外側からは叩けない• このネットワークは、ホストのIPアドレスのネットワークとは別物• (後述する)KubernetesのサービスのIPアドレスのネットワークとも別物(ここがわかりづらい)ここまでのまとめ
flanneldをいったん頭から追い出して、Kubernetesの概念の整理をします
• ノードはKubernetes固有の用語です• 頭が混乱したら、「ホストマシン = ノード」と考えても、大きくは外しません• より正確には、• ノードは、「マスタノード」と「ワーカーノード」の2種類に分けられますホストマシンとノードについて(1)
• ワーカーノードは、Dockerプロセスが稼働するホストで、その上でKubernetes管理下のコンテナ群が稼働します。こちらは「ワーカーノード = ホスト」の理解で問題ありません• マスタノードのほうは、いくつかのKubernetesのサーバプロセス群のことです• これらのプロセスはコンテナ上で動く必要はありません• 「マスタノード」という用語はややミスリーディングに思います(マスタプロセスのほうが適切)# 古い文書ではワーカーノードがMinionと呼ばれていますホストマシンとノードについて(2)
• podはコンテナをグループ化したKubernetes固有の概念です• あるpodインスタンス内のコンテナは、同一のホスト上で稼働します。かつ、(Dockerネットワーク的な意味で)同じIPアドレスを共有します• 密結合なプロセス群、言い換えると、死ぬ時は一緒に死んでほしいようなプロセス群をpodにまとめます• しかし、今日の説明上は、ひとつのpod内にはひとつのコンテナ、というモデルにします• 既に説明したように、ひとつのコンテナにひとつのプロセスのモデルにしているので、今日の説明では、ひとつのpodはひとつのプロセスと対応します• (pauseという特別なプロセスのコンテナがありますが本質的ではないので説明を割愛します)コンテナとpod
• レプリケーションコントローラ(以下rcと略)は、podを複数インスタンス化するKubernetes固有の概念です• 実運用上、podを単一インスタンスで使ってもKubernetesの旨味が少ないので、必要なレプリカ数を指定したrcを設定するのが普通です• rcは指定したレプリカ数分のpodをインスタンス化します。今回の文脈では、レプリカ数分のプロセス起動になります• プロセスがどのホストで起動するかは実行時に決まります(Kubernetesが空いているホストを見つけます)• rcは指定レプリカ数分のpodを維持します。つまり、仮にどこかのpod(=コンテナ=プロセス)が死ぬと、自動で新しいpodが起動しますpodとレプリケーションコントローラ(=rc)
• Kubernetes v1.3以降、rcがレプリカセットとDeploymentという新しい概念で置換されていくようです• 今日の説明は rc のまま進めますfyi, rcとレプリカセットとDeployment
• rcの機能により、podは複数インスタンス状態になります• 今回の場合、同じプログラムから複数プロセスが起動すると考えてください• かつこれらのプロセスがどのホストで動くかは実行時に決まるので、個々のプロセスのIPアドレスは実行時に決まります• サービスは、これらの複数インスタンスに対して単一IPアドレスを割り当てるKubernetesの機能です• 結果的に、サービスのIPアドレスに向けたアクセスが、背後の複数podへ割り振られるのでロードバランサのように振る舞います• 内部的には、各ワーカーノード上で動くkube-proxyというプロセスがiptablesにエントリを追加することで、サービスのIPアドレスを作っています• サービスのIPアドレスはifconfigなどでは見えないアドレスです(後述)podとサービス
• Kubernetesの各サービスのIPアドレスの名前解決にはDNSを使います• SkyDNSというDNS実装が(事実上)Kubernetesに組み込まれています• 実行時に新しいサービスが起動すると、サービス名とIPアドレスのエントリが自動でSkyDNSに登録されます(登録はkube2dnsというプロセスが担当)• 各pod上のプロセスは、サービス名さえわかればサービスにアクセスできます(いわゆるサービスディスカバリ相当の機能になります)• サービス名の命名や、アプリにサービス名をどう与えるかは、アプリケーション開発者の責務です名前解決とSkyDNS
他に知っておくと良い細々したこと:
•Kubernetesの管理用コマンドラインツールです•利用例は後ほど具体例の中で紹介しますkubectl
• 分散KVS• Kubernetesのマスタプロセスが使うデータストアです• SkyDNSおよびflanneldもそれぞれetcdをデータストアとして使います。• 今回の説明においては、etcdとは、どこかにあるただのデータストアと思えば充分です• etcdはコンテナ上にある必要もないですし、マスタノードやワーカーノード上で必ずしも動かす必要はありません• 今日の説明では、(便宜上)マスタノード上でコンテナを使ってetcdを起動しますetcd
•etcdの管理用コマンドラインツールです•利用例は後ほど具体例の中で紹介しますetcdctl
• Kubernetesの各種プロセスをコマンドラインの第一引数で呼び分けられるプログラムです• たとえば hyperkube kubelet と起動すると kubelet プロセスを起動できます• 利用は必須ではないですが、ラクなので今回はhyperkubeを使いますhyperkube
• マスタプロセス群は、apiserverやcontroller-managerやschedulerなどがあります• これらは今後Kubernetesのバージョンが上がると色々と変化すると思うので、一群のプロセス群があるということだけ理解すれば充分です• 唯一気にすべきプロセスはapiserverです• kubectlはapiserverのREST APIを叩くプログラムです。apiserverのアドレスを引数で与える必要があります(同一ホストで動いていれば省略可能)• apiserverはデータストアとしてetcdを使うので、apiserver起動の前にetcd起動が必要で、かつapiserverは起動時にetcdのアドレスを知っている必要があります• 他のKubernetesプロセスたちは、起動時に、apiserverプロセスのアドレスを知っている必要がありますKubernetesのマスタプロセス群
• dockerデーモンプロセス: これがないとコンテナが動かせないので当然必要です• kubelet: ワーカーノードをワーカーノードたらしめるプロセスです。pod(=コンテナ)の起動などを担います• kube-proxy: サービスのIPアドレスを管理します(内部的にiptablesを操作)• flanneld: 異なるホスト上のコンテナ同士をネットワーク的につなぎます(説明済み)各ワーカーノード上で動くプロセス群
Kubernetesを動かしてみます
• 単体ノード上で動かす手順• http://kubernetes.io/docs/getting-started-guides/docker/• http://kubernetes.io/docs/getting-started-guides/docker-multinode/deployDNS/• 複数ノードでの手順• http://kubernetes.io/docs/getting-started-guides/docker-multinode/master/• http://kubernetes.io/docs/getting-started-guides/docker-multinode/worker/手順は下記を参考
• ふたつのホストを使います• ホストのOSは Ubuntu 16.04 ですが、可能な限りディストリビューション依存のない説明をします• 両方のホストがワーカーノードで、かつ片方のホスト上で(コンテナを使って)マスタプロセス群を動かします• ワーカーノード上のプロセス群(kubeletやkube-proxy)も、コンテナを使って動かします• これらのプロセスは、コンテナで動かすことが必須ではありません。将来、普通にapt-getでインストールできるようになれば、そのほうがシンプルですサンプルの構成
1. 全体の準備2. マスタノードになるホスト上での作業3. ワーカーノードになるホスト上での作業4. 自作アプリのサービス化手順のオーバービュー
kubectlコマンドをインストールします基本的には、kubectlコマンドはどのマシンにインストールしても構いません(マスタプロセスのIPアドレスにリーチャブルな場所であれば)。$ export K8S_VERSION=1.2.6$ curl http://storage.googleapis.com/kubernetes-release/release/v${K8S_VERSION}/bin/linux/amd64/kubectl >kubectl$ sudo mv kubectl /usr/local/bin/$ sudo chmod +x /usr/local/bin/kubectlマスタプロセスと異なるホストにインストールした場合、kubectlのコマンドラインオプションの-sでマスタプロセスのホストのIPアドレスとポート(10.140.0.14:8080)を指定する必要があります(あるいは kubeconfigファイルで設定)$ kubectl -s 10.140.0.14:8080 cluster-info全体の準備
• 前述したように、マスタノードという用語はややミスリーディングです• いくつかのマスタプロセスを起動するノードを、単にマスタノードと呼びます• 今回の場合、このホストはワーカーノードにもなりますマスタノードになるホスト
Docker自身のインストール$ sudo apt-get update; sudo apt-get -y upgrade;sudo apt-get -y install docker.io仮にホストでetcdが動いていると邪魔するので、プロセスがいないことを確認仮に動いていたら、止めておく$ sudo systemctl stop etcd$ sudo systemctl disable etcdマスタノードになるホスト上での作業(1)
環境変数設定(利便性のため)$ export MASTER_IP=10.140.0.14 # ホストのIPアドレス。ifconfigで確認$ export K8S_VERSION=1.2.6$ export ETCD_VERSION=2.2.5$ export FLANNEL_VERSION=0.5.5$ export FLANNEL_IFACE=ens4 # ifconfigで確認$ export FLANNEL_IPMASQ=trueマスタノードになるホスト上での作業(2)
• flanneldを動かします。その前にflanneldが依存するetcdを動かします• これらはコンテナで動かす必要はないですが、ラクをするために両方ともコンテナで動かします• ややトリッキーですが、flanneldとetcd専用のDockerデーモンプロセスを起動します• 手順の中の可変項目は、flanneldが使うネットワークアドレスの部分("10.1.0.0/16")です。これは好きに決められますマスタノードになるホスト上での作業(3)
専用Dockerデーモンプロセスの起動$ sudo sh -c 'docker daemon -Hunix:///var/run/docker-bootstrap.sock -p/var/run/docker-bootstrap.pid --iptables=false --ip-masq=false --bridge=none --graph=/var/lib/docker-bootstrap 2> /var/log/docker-bootstrap.log 1> /dev/null &'マスタノードになるホスト上での作業(4)
etcdプロセスの起動(コンテナ内)$ sudo docker -H unix:///var/run/docker-bootstrap.sockrun -d --net=host ¥gcr.io/google_containers/etcd-amd64:${ETCD_VERSION}¥/usr/local/bin/etcd ¥--listen-client-urls=http://127.0.0.1:4001,http://${MASTER_IP}:4001 ¥--advertise-client-urls=http://${MASTER_IP}:4001¥--data-dir=/var/etcd/dataマスタノードになるホスト上での作業(5)
etcdへの初期データ投入$ sudo docker -H unix:///var/run/docker-bootstrap.sock run ¥--net=host ¥gcr.io/google_containers/etcd-amd64:${ETCD_VERSION} ¥etcdctl set /coreos.com/network/config'{ "Network": "10.1.0.0/16" }'マスタノードになるホスト上での作業(6)
通常Dockerデーモンを一時停止$ sudo systemctl stop dockerflanneldプロセスの起動(コンテナ内)$ sudo docker -H unix:///var/run/docker-bootstrap.sockrun -d ¥--net=host --privileged ¥-v /dev/net:/dev/net ¥quay.io/coreos/flannel:${FLANNEL_VERSION} ¥/opt/bin/flanneld ¥--ip-masq=${FLANNEL_IPMASQ} ¥--iface=${FLANNEL_IFACE}マスタノードになるホスト上での作業(7)
flanneldのサブネットのネットワークアドレスを(通常の)Dockerデーモンプロセスに伝えます$ sudo docker -H unix:///var/run/docker-bootstrap.sock exec flanneldコンテナの出力ハッシュ値(=コンテナID) cat /run/flannel/subnet.env入力例$ sudo docker -H unix:///var/run/docker-bootstrap.sock exec195ea9f70770ac20a3f04e02c240fb24a74e1d08ef749f162beab5ee8c905734 cat/run/flannel/subnet.env出力例FLANNEL_NETWORK=10.1.0.0/16FLANNEL_SUBNET=10.1.19.1/24FLANNEL_MTU=1432FLANNEL_IPMASQ=trueマスタノードになるホスト上での作業(8)
$ sudo vi /lib/systemd/system/docker.serviceでExecStart=/usr/bin/docker daemon -H fd://$DOCKER_OPTS --bip=10.1.19.1/24 --mtu=1432と書き換えマスタノードになるホスト上での作業(9)
Dockerデーモンプロセスを再起動します$ sudo /sbin/ifconfig docker0 down$ sudo brctl delbr docker0$ sudo systemctl daemon-reload$ sudo systemctl restart dockerマスタノードになるホスト上での作業(10)
Docker再起動前の確認(抜粋)$ ifconfigdocker0 Link encap:Ethernet HWaddr 02:42:25:65:c5:f3inet addr:10.1.20.1 Bcast:0.0.0.0 Mask:255.255.255.0Docker再起動後の確認(抜粋)$ ifconfigdocker0 Link encap:Ethernet HWaddr 02:42:a5:18:b3:73inet addr:10.1.19.1 Bcast:0.0.0.0 Mask:255.255.255.0flannel0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00inet addr:10.1.19.0 P-t-P:10.1.19.0 Mask:255.255.0.0マスタノードになるホスト上での作業(11)
Docker再起動後のルーティングテーブルの確認$ netstat -rnKernel IP routing tableDestination Gateway Genmask Flags MSSWindow irtt Iface0.0.0.0 10.140.0.1 0.0.0.0 UG 0 00 ens410.1.0.0 0.0.0.0 255.255.0.0 U 0 00 flannel010.1.19.0 0.0.0.0 255.255.255.0 U 0 00 docker010.140.0.1 0.0.0.0 255.255.255.255 UH 0 00 ens4マスタノードになるホスト上での作業(12)
マスタプロセス群およびワーカーノードに必要なプロセス群(kubeletとkube-proxyなど)をhyperkubeで起動します$ sudo docker run ¥--volume=/:/rootfs:ro --volume=/sys:/sys:ro ¥--volume=/var/lib/docker/:/var/lib/docker:rw ¥--volume=/var/lib/kubelet/:/var/lib/kubelet:rw ¥--volume=/var/run:/var/run:rw ¥--net=host --privileged=true --pid=host -d ¥gcr.io/google_containers/hyperkube-amd64:v${K8S_VERSION} ¥/hyperkube kubelet --allow-privileged=true ¥--api-servers=http://localhost:8080 ¥--v=2 --address=0.0.0.0 --enable-server ¥--hostname-override=127.0.0.1 ¥--config=/etc/kubernetes/manifests-multi --containerized ¥--cluster-dns=10.0.0.10 --cluster-domain=cluster.localマスタノードになるホスト上での作業(13)
Kubernetesのマスタプロセスの動作確認$ kubectl cluster-infoKubernetes master is running at http://localhost:8080マスタノードになるホスト上での作業(14)
SkyDNSをpodとして動かします。$ curl http://kubernetes.io/docs/getting-started-guides/docker-multinode/skydns.yaml.in > skydns.yaml.in$ export DNS_REPLICAS=1$ export DNS_DOMAIN=cluster.local # 自分で決めてよいドメイン名$ export DNS_SERVER_IP=10.0.0.10 # 自分で決めてよいDNSサーバのIPアドレス(KubernetesのサービスとしてIPアドレス)$ sed -e"s/{{ pillar¥['dns_replicas'¥] }}/${DNS_REPLICAS}/g;s/{{ pillar¥['dns_domain'¥] }}/${DNS_DOMAIN}/g;s/{{ pillar¥['dns_server'¥] }}/${DNS_SERVER_IP}/g" skydns.yaml.in > ./skydns.yamlマスタノードになるホスト上での作業(15)
rcおよびサービスの作成(skydns.yamlの中身はrcとサービス)$ kubectl create -f ./skydns.yamlマスタノードになるホスト上での作業(15)
$ kubectl cluster-infoKubernetes master is running at http://localhost:8080KubeDNS is running at http://localhost:8080/api/v1/proxy/namespaces/kube-system/services/kube-dns確認(このfailureの原因は不明)$ curl http://localhost:8080/api/v1/proxy/namespaces/kube-system/services/kube-dns{"kind": "Status","apiVersion": "v1","metadata": {},"status": "Failure","message": "no endpoints available for service ¥"kube-dns¥"","reason": "ServiceUnavailable","code": 503}SkyDNSの動作確認(1)
$ kubectl get --all-namespaces svcNAMESPACE NAME CLUSTER-IP EXTERNAL-IP PORT(S)AGEdefault kubernetes 10.0.0.1 <none> 443/TCP2mkube-system kube-dns 10.0.0.10 <none>53/UDP,53/TCP 1m$ kubectl get --all-namespaces epNAMESPACE NAME ENDPOINTS AGEdefault kubernetes 10.140.0.14:6443 2mkube-system kube-dns 10.1.19.2:53,10.1.19.2:53 1mSkyDNSの動作確認(2)
$ dig @10.0.0.10 cluster.local.(抜粋);; ANSWER SECTION:cluster.local. 30 IN A 10.1.19.2cluster.local. 30 IN A 127.0.0.1cluster.local. 30 IN A 10.0.0.10cluster.local. 30 IN A 10.0.0.1$ dig @10.1.19.2 cluster.local.も動くが、このIPアドレスは状況によって変わりうるので依存してはいけないSkyDNSの動作確認(3)
• 最初のホスト上でflanneldを設定しました• このホスト上でマスタプロセス群を起動しました(apiserverなど)• このホストをワーカーノードにしました(kubeletとkube-proxyの起動)• SkyDNSをKubernetesのサービスとして起動しました(10.0.0.10のIPアドレスでアクセス可能)ここまでのまとめ
Docker自身のインストール$ sudo apt-get update; sudo apt-get -y upgrade;sudo apt-get -y install docker.io環境変数設定(利便性のため)$ export MASTER_IP=10.140.0.14 # マスタノードのホストのIPアドレス$ export K8S_VERSION=1.2.6$ export FLANNEL_VERSION=0.5.5$ export FLANNEL_IFACE=ens4 # ifconfigで確認$ export FLANNEL_IPMASQ=trueワーカーノードになるホスト上での作業(1)
• マスタノードと同じく、flanneldをコンテナで起動します• etcdはマスタノード上のetcdを参照します• flanneldの起動はマスタノードと同じ手順です専用Dockerデーモンプロセスの起動$ sudo sh -c 'docker daemon -H unix:///var/run/docker-bootstrap.sock -p /var/run/docker-bootstrap.pid --iptables=false --ip-masq=false --bridge=none --graph=/var/lib/docker-bootstrap 2> /var/log/docker-bootstrap.log 1> /dev/null &'通常Dockerデーモンを一時停止$ sudo systemctl stop dockerワーカーノードになるホスト上での作業(2)
flanneldプロセスの起動(コンテナ内)$ sudo docker -H unix:///var/run/docker-bootstrap.sock run -d ¥--net=host --privileged -v /dev/net:/dev/net ¥quay.io/coreos/flannel:${FLANNEL_VERSION} ¥/opt/bin/flanneld ¥--ip-masq=${FLANNEL_IPMASQ} ¥--etcd-endpoints=http://${MASTER_IP}:4001 ¥--iface=${FLANNEL_IFACE}ワーカーノードになるホスト上での作業(3)
flanneldのサブネットのネットワークアドレスを(通常の)Dockerデーモンプロセスに伝えます$ sudo docker -H unix:///var/run/docker-bootstrap.sock exec flanneldコンテナの出力ハッシュ値(=コンテナID) cat /run/flannel/subnet.env出力例FLANNEL_NETWORK=10.1.0.0/16FLANNEL_SUBNET=10.1.79.1/24FLANNEL_MTU=1432FLANNEL_IPMASQ=true$ sudo vi /lib/systemd/system/docker.serviceでExecStart=/usr/bin/docker daemon -H fd:// $DOCKER_OPTS --bip=10.1.79.1/24 --mtu=1432と書き換えワーカーノードになるホスト上での作業(4)
Dockerデーモンプロセスを再起動します$ sudo /sbin/ifconfig docker0 down$ sudo brctl delbr docker0$ sudo systemctl daemon-reload$ sudo systemctl restart dockerワーカーノードになるホスト上での作業(5)
確認はifconfigおよびnetstat -rnで実施再起動後のルーティングテーブルの確認$ netstat -rnKernel IP routing tableDestination Gateway Genmask Flags MSSWindow irtt Iface0.0.0.0 10.140.0.1 0.0.0.0 UG 0 00 ens410.1.0.0 0.0.0.0 255.255.0.0 U 0 00 flannel010.1.79.0 0.0.0.0 255.255.255.0 U 0 00 docker010.140.0.1 0.0.0.0 255.255.255.255 UH 0 00 ens4ワーカーノードになるホスト上での作業(6)
ワーカーノードに必要なプロセス(kubelet)をhyperkubeで起動します$ sudo docker run ¥--volume=/:/rootfs:ro --volume=/sys:/sys:ro ¥--volume=/dev:/dev ¥--volume=/var/lib/docker/:/var/lib/docker:rw ¥--volume=/var/lib/kubelet/:/var/lib/kubelet:rw ¥--volume=/var/run:/var/run:rw ¥--net=host --privileged=true --pid=host -d ¥gcr.io/google_containers/hyperkube-amd64:v${K8S_VERSION} ¥/hyperkube kubelet ¥--allow-privileged=true --api-servers=http://${MASTER_IP}:8080 ¥--v=2 --address=0.0.0.0 --enable-server --containerized ¥--cluster-dns=10.0.0.10 --cluster-domain=cluster.localワーカーノードになるホスト上での作業(7)
ワーカーノードに必要なプロセス(kube-proxy)をhyperkubeで起動します$ sudo docker run -d --net=host --privileged ¥gcr.io/google_containers/hyperkube-amd64:v${K8S_VERSION} ¥/hyperkube proxy ¥--master=http://${MASTER_IP}:8080 --v=2ワーカーノードになるホスト上での作業(8)
•ふたつ目のホスト上でflanneldを設定しました•このホストをワーカーノードにしました(kubeletとkube-proxyの起動)ここまでのまとめ
$ kubectl -s 10.140.0.14:8080 cluster-infoKubernetes master is running at 10.140.0.14:8080KubeDNS is running at10.140.0.14:8080/api/v1/proxy/namespaces/kube-system/services/kube-dnsサービスの確認$ kubectl -s 10.140.0.14:8080 get --all-namespaces svcNAMESPACE NAME CLUSTER-IP EXTERNAL-IP PORT(S)AGEdefault kubernetes 10.0.0.1 <none> 443/TCP47mkube-system kube-dns 10.0.0.10 <none>53/UDP,53/TCP 45mKubernetesの基本的な動作確認(1)
ノードの確認$ kubectl get nodesNAME STATUS AGE127.0.0.1 Ready 52mubuntu16k5 Ready 16mKubernetesの基本的な動作確認(2)
自作Node.jsアプリをKubernetes上のサービスとして動かしてみる
server.js =>var http = require('http');var handleRequest = function(request, response) {response.writeHead(200);response.end("Hello World");}var www = http.createServer(handleRequest);www.listen(8888);サンプルアプリケーションのDockerイメージを準備(1)
Dockerfile =>FROM node:latestEXPOSE 8888COPY server.js .CMD node server.js$ sudo docker build -t mynode:latest .$ sudo docker images # 確認サンプルアプリケーションのDockerイメージを準備(2)
このDockerイメージを複数ホストから取得できるためにレジストリに登録する必要があります(自前でdockerレジストリを立てるのがベストですが、今回はDockerHubで代用します)$ docker login$ docker tag mynode:latest guest/mynode # guestの部分はDockerHubのログインID$ docker push guest/mynodeDockerイメージをレジストリに登録
mynode.yaml =>apiVersion: v1kind: ReplicationControllermetadata:name: my-nodespec:replicas: 2template:metadata:labels:app: samplespec:containers:- name: mynodeimage: guest/mynodeports:- containerPort: 8888rc用の設定ファイルReplicationController(rc)の設定ファイルこのrcの識別名(開発者の命名)レプリケーション数の指定Dockerイメージの指定(on DockerHub)ラベル(keyとvalue両方とも開発者の命名)
mynode-svc.yaml =>apiVersion: v1kind: Servicemetadata:name: frontendlabels:app: samplespec:ports:- port: 8888selector:app: sampleサービス用の設定ファイル(selectorでmynode.yamlを参照する関係)サービス(svc)の設定ファイルこのサービスの識別名(開発者の命名)ラベル(開発者の命名)rc(やpod)のラベルでセレクト
起動は$ kubectl create -f mynode.yaml$ kubectl create -f mynode-svc.yaml削除する時は$ kubectl delete -f mynode-svc.yaml$ kubectl delete -f mynode.yaml設定ファイルによる起動および削除
まずrcを起動(=暗黙にpodを起動)してみます$ kubectl create -f mynode.yamlrcを起動(=暗黙にpodを起動)
podの確認$ kubectl get --all-namespaces poNAMESPACE NAME READY STATUS RESTARTS AGEdefault k8s-master-127.0.0.1 4/4 Running 0 50mdefault k8s-proxy-127.0.0.1 1/1 Running 0 50mdefault my-node-ejvv9 1/1 Running 0 10sdefault my-node-lm62r 1/1 Running 0 10skube-system kube-dns-v10-suqsw 4/4 Running 0 48mrcの確認$ kubectl get --all-namespaces rcNAMESPACE NAME DESIRED CURRENT AGEdefault my-node 2 2 36skube-system kube-dns-v10 1 1 49mpodとrcの確認
サービス(svc)はまだ存在していません$ kubectl get --all-namespaces svcNAMESPACE NAME CLUSTER-IP EXTERNAL-IP PORT(S)AGEdefault kubernetes 10.0.0.1 <none> 443/TCP51mkube-system kube-dns 10.0.0.10 <none> 53/UDP,53/TCP49mエンドポイント(ep)もまだ存在しません$ kubectl get --all-namespaces epNAMESPACE NAME ENDPOINTS AGEdefault kubernetes 10.140.0.14:6443 51mkube-system kube-dns 10.1.19.2:53,10.1.19.2:53 49mサービスとエンドポイントの確認
サービスを起動してみます$ kubectl create -f mynode-svc.yamlサービス(svc)の起動
サービス確認$ kubectl get --all-namespaces svcNAMESPACE NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGEdefault frontend 10.0.0.206 <none> 8888/TCP 21sdefault kubernetes 10.0.0.1 <none> 443/TCP 53mkube-system kube-dns 10.0.0.10 <none> 53/UDP,53/TCP 51mエンドポイント確認$ kubectl get --all-namespaces epNAMESPACE NAME ENDPOINTS AGEdefault frontend 10.1.19.3:8888,10.1.79.2:8888 58sdefault kubernetes 10.140.0.14:6443 53mkube-system kube-dns 10.1.19.2:53,10.1.19.2:53 52mサービスとエンドポイントの確認
サービスのIPアドレスにアクセス$ curl http://10.0.0.206:8888Hello Worldアプリの動作確認
Podの確認$ kubectl describe po my-node-ejvv9Name: my-node-ejvv9Namespace: defaultNode: ubuntu16k5/10.140.0.15Start Time: Wed, 20 Jul 2016 09:23:11 +0000Labels: app=sampleStatus: RunningIP: 10.1.79.2Controllers: ReplicationController/my-nodeContainers:mynode:Container ID:docker://daf3fb9f2217ef40226aab040bd64d6f6f0d5bdcd0318e5628e9af07adcb6504Image: guest/mynode以下略podの詳細
レプリケーションの確認$ kubectl describe rc my-nodeName: my-nodeNamespace: defaultImage(s): guest/mynodeSelector: app=sampleLabels: app=sampleReplicas: 2 current / 2 desiredPods Status: 2 Running / 0 Waiting / 0 Succeeded / 0 FailedNo volumes.Events:FirstSeen LastSeen Count FromSubobjectPath Type Reason Message--------- -------- ----- ---- ------------- -------- ------ -------5m 5m 1 {replication-controller }Normal SuccessfulCreate Created pod: my-node-ejvv95m 5m 1 {replication-controller }Normal SuccessfulCreate Created pod: my-node-lm62rレプリケーション(rc)の確認
サービスの確認$ kubectl describe svc frontendName: frontendNamespace: defaultLabels: app=sampleSelector: app=sampleType: ClusterIPIP: 10.0.0.206Port: <unset> 8888/TCPEndpoints: 10.1.19.3:8888,10.1.79.2:8888Session Affinity: NoneNo events.サービスの詳細
エンドポイントの確認(:コンテナのIPアドレスの確認)$ kubectl describe ep frontendName: frontendNamespace: defaultLabels: app=sampleSubsets:Addresses: 10.1.19.3,10.1.79.2NotReadyAddresses: <none>Ports:Name Port Protocol---- ---- --------<unset> 8888 TCPNo events.エンドポイントの確認
$ kubectl scale --replicas=5rc/my-nodereplicationcontroller "my-node"scaledrcのスケールアウト検証
$ kubectl get --all-namespaces rcNAMESPACE NAME DESIRED CURRENTAGEdefault my-node 5 5 7mkube-system kube-dns-v10 1 155mrcのスケールアウト検証の確認(1)
$ kubectl get --all-namespaces poNAMESPACE NAME READY STATUS RESTARTS AGEdefault k8s-master-127.0.0.1 4/4 Running 0 57mdefault k8s-proxy-127.0.0.1 1/1 Running 0 57mdefault my-node-3blsf 1/1 Running 0 39sdefault my-node-a2015 1/1 Running 0 39sdefault my-node-ejvv9 1/1 Running 0 7mdefault my-node-lm62r 1/1 Running 0 7mdefault my-node-u5gxt 1/1 Running 0 39skube-system kube-dns-v10-suqsw 4/4 Running 0 56mrcのスケールアウト検証の確認(2)
$ kubectl get --all-namespaces epNAMESPACE NAME ENDPOINTSAGEdefault frontend10.1.19.3:8888,10.1.19.4:8888,10.1.79.2:8888 + 2more... 5mdefault kubernetes 10.140.0.14:644358mkube-system kube-dns10.1.19.2:53,10.1.19.2:5356mrcのスケールアウト検証の確認(3)
$ kubectl describe ep frontendName: frontendNamespace: defaultLabels: app=sampleSubsets:Addresses:10.1.19.3,10.1.19.4,10.1.79.2,10.1.79.3,10.1.79.4NotReadyAddresses: <none>Ports:Name Port Protocol---- ---- --------<unset> 8888 TCPNo events.片方のホストに2つ(10.1.19.3,10.1.19.4)、もうひとつのホストに3つ(10.1.79.2,10.1.79.3,10.1.79.4)のpodがあるRCのスケールアウト検証の確認(4)
podが増えようと、サービスとしての見え方は不変$ kubectl get --all-namespaces svcNAMESPACE NAME CLUSTER-IP EXTERNAL-IPPORT(S) AGEdefault frontend 10.0.0.206 <none>8888/TCP 5mdefault kubernetes 10.0.0.1 <none>443/TCP 58mkube-system kube-dns 10.0.0.10 <none>53/UDP,53/TCP 56mrcのスケールアウト検証の確認(5)
$ kubectl describe po my-node-3blsfName: my-node-3blsfNamespace: defaultNode: ubuntu16k5/10.140.0.15Start Time: Wed, 20 Jul 2016 09:29:54 +0000(略)個々のpodの物理位置の確認(Nodeの行)
$ kubectl exec -it my-node-3blsf sh=> 別ホスト上のpodへもログイン可能なので、Dockerレベルのコンテナへのログイン(docker exec -it)より便利です特定podへログイン
$ kubectl logs my-node-3blsftailfも可能$ kubectl logs -f my-node-3blsf特定podのログの確認
$ sudo docker ps |grep mynode9b8ecdb7a42f guest/mynode"/bin/sh -c 'node ser" 15 minutes ago Up 15 minutesk8s_mynode.6062cb3_my-node-a2015_default_841729f4-4e5c-11e6-930a-42010a8c000e_a8947e6850e8cd85abec guest/mynode"/bin/sh -c 'node ser" 21 minutes ago Up 21 minutesk8s_mynode.6062cb3_my-node-lm62r_default_94564430-4e5b-11e6-930a-42010a8c000e_bcf722c3fyi, Dockerレベルでコンテナの詳細を確認$ sudo docker inspect 9b8ecdb7a42f(略)fyi, Dockerレベルで確認
• たとえばDockerレベルでコンテナを落としたり、ホストOSからDockerコンテナ上のプロセスをkill• たとえば特定のマシン(VMインスタンス)を落とすテスト=> レプリケーションの数が維持される特定のpodを落とすテスト
• 自作アプリをサービスとして起動しました• rcにより、pod(=コンテナ=プロセス)を複数インスタンス化しました• podのインスタンス数がどうあれ、サービスにはサービスのIPアドレスで常にアクセス可能です• 個々のpodの障害調査をしたければ、シェルで直接ログインしたりログの監視が可能ですここまでのまとめ
Kubernetesのネットワーク
各pod内からはサービス名つまりcurl http://frontend:8888でお互いが見えます=> DNSが返すIPアドレスは、サービスのIPアドレス(DockerコンテナのIPアドレスでもないし、ホストのIPアドレスでもない)名前解決(DNS)
$ dig @10.0.0.10 frontend.default.svc.cluster.local.(略);; ANSWER SECTION:frontend.default.svc.cluster.local. 30 IN A10.0.0.206=> DNSのFQDNは frontend.default.svc.cluster.local.フォーマット:サービス名.ネームスペース名.svc.cluster.local.ホストからの名前解決
• ここまでの話:• DNSでサービス名からサービスのIPアドレスがひけるようになりました• ここからの話:• このサービスのIPアドレスから、サービスにひもづくpodにたどりつく必要があります• rcのメカニズムにより、サービスにひもづくpodは複数ありうるので、どこかのpodにたどりつく必要があります• 正確に言うと、pod内のコンテナにたどりつく必要がありますネットワーク詳解
• サービスのIPアドレスはifconfigの世界には存在しないアドレスです• iptablesで、サービスのIPアドレスからpod(=コンテナ)のアドレスへ宛先アドレスを書き換えます• rcのメカニズムで複数のpodがある場合、iptablesのロードバランス機能で振り分けます• iptablesにサービスのIPアドレスを追加するのはkube-proxyの役割です• pod(=コンテナ)のアドレス宛のパケットをホストのIPアドレス宛に変えるのはflanneldの役割です• (このルーティングテーブルはetcdに入っています)ネットワークの動作概要
10.0.0.206宛のパケットはiptablesでランダムに5つのどれかに行きます(rcのレプリカ数が5の場合):$ sudo iptables-save | grep 10.0.0.206-A KUBE-SERVICES -d 10.0.0.206/32 -p tcp -m comment --comment "default/frontend: cluster IP" -m tcp --dport 8888 -j KUBE-SVC-GYQQTB6TY565JPRW$ sudo iptables-save |grep KUBE-SVC-GYQQTB6TY565JPRW:KUBE-SVC-GYQQTB6TY565JPRW - [0:0]-A KUBE-SERVICES -d 10.0.0.206/32 -p tcp -m comment --comment "default/frontend: cluster IP" -m tcp --dport 8888 -j KUBE-SVC-GYQQTB6TY565JPRW-A KUBE-SVC-GYQQTB6TY565JPRW -m comment --comment "default/frontend:" -m statistic --mode random --probability 0.20000000019 -j KUBE-SEP-IABZAQPI4OCAAEYI-A KUBE-SVC-GYQQTB6TY565JPRW -m comment --comment "default/frontend:" -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-KOOQP76EBZUHPEOS-A KUBE-SVC-GYQQTB6TY565JPRW -m comment --comment "default/frontend:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-R2LUGYH3W6MZDZRV-A KUBE-SVC-GYQQTB6TY565JPRW -m comment --comment "default/frontend:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-RHTBT7WLGW2VONI3-A KUBE-SVC-GYQQTB6TY565JPRW -m comment --comment "default/frontend:" -j KUBE-SEP-DSHEFNPOTRMM5FWSiptablesを確認(1)
$ sudo iptables-save |grep KUBE-SEP-DSHEFNPOTRMM5FWS:KUBE-SEP-DSHEFNPOTRMM5FWS - [0:0]-A KUBE-SEP-DSHEFNPOTRMM5FWS -s 10.1.79.4/32 -m comment--comment "default/frontend:" -j KUBE-MARK-MASQ-A KUBE-SEP-DSHEFNPOTRMM5FWS -p tcp -m comment --comment"default/frontend:" -m tcp -j DNAT --to-destination10.1.79.4:8888-A KUBE-SVC-GYQQTB6TY565JPRW -m comment --comment"default/frontend:" -j KUBE-SEP-DSHEFNPOTRMM5FWS=> ある確率で 10.0.0.206:8888宛のパケットは 10.1.79.4:8888宛のパケットへ変換されるiptablesを確認(2)
$ netstat -rnKernel IP routing tableDestination Gateway Genmask Flags MSSWindow irtt Iface0.0.0.0 10.140.0.1 0.0.0.0 UG 0 00 ens410.1.0.0 0.0.0.0 255.255.0.0 U 0 00 flannel010.1.19.0 0.0.0.0 255.255.255.0 U 0 00 docker010.140.0.1 0.0.0.0 255.255.255.255 UH 0 00 ens4=> 10.1.79.4:8888 宛のパケットはflanneldへ行くホストのルーティングテーブルを確認
$ etcdctl ls --recursive/coreos.com/network/subnets/coreos.com/network/subnets/10.1.19.0-24/coreos.com/network/subnets/10.1.79.0-24$ etcdctl get/coreos.com/network/subnets/10.1.79.0-24{"PublicIP":"10.140.0.15"}=> "10.140.0.15"は、10.1.79.0/24のpod(コンテナ)が動いているホストのIPアドレスflanneldのルーティングテーブルを確認
•iptablesでサービスのIPアドレス宛のパケットがpodのIPアドレス宛になる•pod宛のパケットはflanneldの力で、そのpodが動いているホスト宛のパケットになるここまでのまとめ
10.0.0.206をホストの外から叩けるようにするには、NodePort(orLoadBalancer)でポートを外に見せるmynode-svc.yaml =>apiVersion: v1kind: Servicemetadata:name: frontendlabels:app: samplespec:type: NodePortports:- port: 8888selector:app: sampleホストの外にポートを公開するには動作は異なりますが、感覚的にはDockerでポートエクスポートする感じ
• Kubernetesは初見でかなり複雑怪奇に見えますが、きちんと分解すればなんとか理解できる(はず)• ちょっとした考察• おかしなことが起きた時、プロセスは潔く死んだほうがKubernetesに優しそうです• iptablesを使っている限り、負荷分散が(ラウンドロビンより)リッチになる見込みがない部分は賛否両論あるかもしれません(LBとしては、ある種の割り切り)まとめ
• メインのプログラミング言語: Java、JavaScript、Swift(一部)• 使っているミドルウェアの言語: Scala(Spark、Kafka)、Go(Kubernetes)• OS(Linux)、JVM、アルゴリズム、ミドルウェア、ネットワーク、ブラウザそれぞれの専門家は歓迎します• 本物の機械学習ができるデータがあります(会社組織というアーキテクチャが分析対象)• 大規模開発(東京、大阪、上海、シンガポール、チェンナイ)なので、日本なんてどうでもいいと思うタフさ(鈍感さ)と抽象化して大枠をとらえる力があると良いと思います最後にJTFのスポンサーなので人材募集(株式会社ワークスアプリケーションズ)

Recommended

PDF
Dockerの仕組みとIIJ社内での利用例
PDF
普通のRailsアプリをdockerで本番運用する知見
PDF
最近のKubernetesとDocker Machine/Swarmの話
PDF
DockerからKubernetesへのシフト
PDF
Kubernetesを触ってみた
PDF
Dockerで遊んでみよっかー YAPC::Asia Tokyo 2014
PDF
【dots. IT勉強会】開発環境のDocker化
PDF
Using LXC on Production
PDF
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】
PPTX
Kubernetes超入門 with java
PDF
Docker, Kubernetes and OpenShift v3
PDF
Rancher/Kubernetes入門ハンズオン資料~第2回さくらとコンテナの夕べ #さくらの夕べ 番外編
PPTX
Docker & Kubernetes基礎
PDF
GKEで半年運用してみた
PDF
Weaveを試してみた
PDF
机上の Kubernetes - 形式手法で見るコンテナオーケストレーション #NGK2016B
PPTX
今さら聞けない人のためのDocker超入門 – OpenStack最新情報セミナー 2015年4月
PDF
Docker Swarm入門
PDF
Dockerの基本と応用~快適コンテナライフを実現するArukas~
PPTX
Docker超入門
PDF
【18-E-3】クラウド・ネイティブ時代の2016年だから始める Docker 基礎講座
PDF
DockerでWordPressサイトを開発してみよう
 
PDF
Docker on RHEL & Project Atomic 入門 - #Dockerjp 4
PDF
Dockerの利用事例
PPTX
Docker地雷n本勝負
PPTX
CAMPHOR- day 2020 - Docker 超入門
PDF
ECS-CLI in Action
PDF
Kubernetes in 30 minutes (2017/03/10)
PDF
Jenkins 2.0 最新事情 〜Make Jenkins Great Again〜

More Related Content

PDF
Dockerの仕組みとIIJ社内での利用例
PDF
普通のRailsアプリをdockerで本番運用する知見
PDF
最近のKubernetesとDocker Machine/Swarmの話
PDF
DockerからKubernetesへのシフト
PDF
Kubernetesを触ってみた
PDF
Dockerで遊んでみよっかー YAPC::Asia Tokyo 2014
PDF
【dots. IT勉強会】開発環境のDocker化
PDF
Using LXC on Production
Dockerの仕組みとIIJ社内での利用例
普通のRailsアプリをdockerで本番運用する知見
最近のKubernetesとDocker Machine/Swarmの話
DockerからKubernetesへのシフト
Kubernetesを触ってみた
Dockerで遊んでみよっかー YAPC::Asia Tokyo 2014
【dots. IT勉強会】開発環境のDocker化
Using LXC on Production

What's hot

PDF
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】
PPTX
Kubernetes超入門 with java
PDF
Docker, Kubernetes and OpenShift v3
PDF
Rancher/Kubernetes入門ハンズオン資料~第2回さくらとコンテナの夕べ #さくらの夕べ 番外編
PPTX
Docker & Kubernetes基礎
PDF
GKEで半年運用してみた
PDF
Weaveを試してみた
PDF
机上の Kubernetes - 形式手法で見るコンテナオーケストレーション #NGK2016B
PPTX
今さら聞けない人のためのDocker超入門 – OpenStack最新情報セミナー 2015年4月
PDF
Docker Swarm入門
PDF
Dockerの基本と応用~快適コンテナライフを実現するArukas~
PPTX
Docker超入門
PDF
【18-E-3】クラウド・ネイティブ時代の2016年だから始める Docker 基礎講座
PDF
DockerでWordPressサイトを開発してみよう
 
PDF
Docker on RHEL & Project Atomic 入門 - #Dockerjp 4
PDF
Dockerの利用事例
PPTX
Docker地雷n本勝負
PPTX
CAMPHOR- day 2020 - Docker 超入門
PDF
ECS-CLI in Action
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】
Kubernetes超入門 with java
Docker, Kubernetes and OpenShift v3
Rancher/Kubernetes入門ハンズオン資料~第2回さくらとコンテナの夕べ #さくらの夕べ 番外編
Docker & Kubernetes基礎
GKEで半年運用してみた
Weaveを試してみた
机上の Kubernetes - 形式手法で見るコンテナオーケストレーション #NGK2016B
今さら聞けない人のためのDocker超入門 – OpenStack最新情報セミナー 2015年4月
Docker Swarm入門
Dockerの基本と応用~快適コンテナライフを実現するArukas~
Docker超入門
【18-E-3】クラウド・ネイティブ時代の2016年だから始める Docker 基礎講座
DockerでWordPressサイトを開発してみよう
 
Docker on RHEL & Project Atomic 入門 - #Dockerjp 4
Dockerの利用事例
Docker地雷n本勝負
CAMPHOR- day 2020 - Docker 超入門
ECS-CLI in Action

Viewers also liked

PDF
Kubernetes in 30 minutes (2017/03/10)
PDF
Jenkins 2.0 最新事情 〜Make Jenkins Great Again〜
PDF
遅いクエリと向き合う仕組み #CybozuMeetup
 
PPTX
WalB: Real-time and Incremental Backup System for Block Devices
PDF
3000社の業務データ絞り込みを支える技術
PDF
なんたって”DevQA” アジャイル開発とQAの合体が改善を生む - 永田 敦 氏 #postudy
PDF
サイボウズのサービスを支えるログ基盤
PDF
フロー効率性とリソース効率性について #xpjug
PDF
形態素解析
PPTX
導入に困っているあなたに贈る スクラム導入コミュニケーション術
PDF
小さく始める大規模スクラム
PDF
[RSGT2017] つらい問題に出会ったら
PDF
市場価値で給料が決まるサイボウズの社員だけど、転職ドラフトに参加して給与交渉に挑戦してみました
PPTX
Api Strat Portland 2017 Serverless Extensibility talk
PDF
すべてを自動化せよ! 〜生産性向上チームの挑戦〜
PDF
サイボウズのフロントエンド開発 現在とこれからの挑戦
PPTX
すべての人にチームワークを サイボウズのアクセシビリティ
PDF
離れた場所でも最高のチームワークを実現する方法 ーサイボウズ開発チームのリモートワーク事例ー
PDF
あなたの開発チームには、チームワークがあふれていますか?
Kubernetes in 30 minutes (2017/03/10)
Jenkins 2.0 最新事情 〜Make Jenkins Great Again〜
遅いクエリと向き合う仕組み #CybozuMeetup
 
WalB: Real-time and Incremental Backup System for Block Devices
3000社の業務データ絞り込みを支える技術
なんたって”DevQA” アジャイル開発とQAの合体が改善を生む - 永田 敦 氏 #postudy
サイボウズのサービスを支えるログ基盤
フロー効率性とリソース効率性について #xpjug
形態素解析
導入に困っているあなたに贈る スクラム導入コミュニケーション術
小さく始める大規模スクラム
[RSGT2017] つらい問題に出会ったら
市場価値で給料が決まるサイボウズの社員だけど、転職ドラフトに参加して給与交渉に挑戦してみました
Api Strat Portland 2017 Serverless Extensibility talk
すべてを自動化せよ! 〜生産性向上チームの挑戦〜
サイボウズのフロントエンド開発 現在とこれからの挑戦
すべての人にチームワークを サイボウズのアクセシビリティ
離れた場所でも最高のチームワークを実現する方法 ーサイボウズ開発チームのリモートワーク事例ー
あなたの開発チームには、チームワークがあふれていますか?

Similar to Kubernetesにまつわるエトセトラ(主に苦労話)

PDF
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
PPTX
今さら聞けない人のためのKubernetes超入門
PPTX
45分で理解するKubernetesの世界
PDF
Kubernetes雑にまとめてみた 2020年8月版
PDF
[GKE & Spanner 勉強会] GKE 入門
PDF
Kubernetes雑にまとめてみた 2019年12月版
PDF
Kubernetes meetup-tokyo-13-customizing-kubernetes-for-ml-cluster
PDF
最速・最短・最簡単でKubernetesを始めるハウツー with k0s
PDF
How to Schedule Machine Learning Workloads Nicely In Kubernetes #CNDT2020 / C...
PDF
Kubernetes Cluster Adminやってました #con_rider
PPTX
Kubernetes ときどき Serverless -- cndjp第1回勉強会
PDF
DockerとKubernetesが作る未来
PDF
6 月 18 日 Next - Kubernetes のコンテナ技術ですべてをシンプルに
PPTX
今さら聞けない人のための K8s超入門 Big Sur対応版 CNDO2021 ショートバージョン
PPTX
今さら聞けない人のための K8s超入門 Big Sur対応版
PPTX
Kubernetesオンラインセミナー kubernetesの始め方
PDF
Kubernetes上のWindows Server コンテナーのマイクロサービス間分離
PDF
Kubernetes1.9でWindowsコンテナーをクラスタ化
PDF
半日でわかる コンテナー技術 (応用編)
PDF
【K.M】Kubernetes.pdf
Kubernetesのしくみ やさしく学ぶ 内部構造とアーキテクチャー
今さら聞けない人のためのKubernetes超入門
45分で理解するKubernetesの世界
Kubernetes雑にまとめてみた 2020年8月版
[GKE & Spanner 勉強会] GKE 入門
Kubernetes雑にまとめてみた 2019年12月版
Kubernetes meetup-tokyo-13-customizing-kubernetes-for-ml-cluster
最速・最短・最簡単でKubernetesを始めるハウツー with k0s
How to Schedule Machine Learning Workloads Nicely In Kubernetes #CNDT2020 / C...
Kubernetes Cluster Adminやってました #con_rider
Kubernetes ときどき Serverless -- cndjp第1回勉強会
DockerとKubernetesが作る未来
6 月 18 日 Next - Kubernetes のコンテナ技術ですべてをシンプルに
今さら聞けない人のための K8s超入門 Big Sur対応版 CNDO2021 ショートバージョン
今さら聞けない人のための K8s超入門 Big Sur対応版
Kubernetesオンラインセミナー kubernetesの始め方
Kubernetes上のWindows Server コンテナーのマイクロサービス間分離
Kubernetes1.9でWindowsコンテナーをクラスタ化
半日でわかる コンテナー技術 (応用編)
【K.M】Kubernetes.pdf

More from Works Applications

PDF
RDB脳でCassandra / MSAを始めた僕達が、分散Drivenなトランザクション管理にたどり着くまで / A journey to a...
PDF
SpotBugs(FindBugs)による 大規模ERPのコード品質改善
PDF
Gitで安定マスターブランチを手に入れる
PDF
Cassandraに不向きなcassandraデータモデリング基礎 / Data Modeling concepts for NoSQL weak point
PDF
新入社員が多い中で効果的なレビューを行うための方法 レビューの準備からフィードバックまでの工夫
ODP
Javaでつくる本格形態素解析器
PDF
Demystifying kubernetes
PDF
Global Innovation Nights - Spark
PDF
Enterprise UI/UX - design as code
PDF
Erpと自然言語処理
RDB脳でCassandra / MSAを始めた僕達が、分散Drivenなトランザクション管理にたどり着くまで / A journey to a...
SpotBugs(FindBugs)による 大規模ERPのコード品質改善
Gitで安定マスターブランチを手に入れる
Cassandraに不向きなcassandraデータモデリング基礎 / Data Modeling concepts for NoSQL weak point
新入社員が多い中で効果的なレビューを行うための方法 レビューの準備からフィードバックまでの工夫
Javaでつくる本格形態素解析器
Demystifying kubernetes
Global Innovation Nights - Spark
Enterprise UI/UX - design as code
Erpと自然言語処理

Kubernetesにまつわるエトセトラ(主に苦労話)


[8]ページ先頭

©2009-2025 Movatter.jp