2019年9月27日に開催されたKubernetes Meetup Tokyo #23にブログ枠で参加させていただいたので、その模様について書いていきます。
会場
会場は渋谷ストリームの隣に誕生した渋谷スクランブルスクエアです。ビルの正式オープンが11月からとのことで絶賛内装工事中でした。 渋谷駅直結でとても便利な立地です。スポンサーはCyberAgent社です。
Session
ゼロから始めるKubernetes Controller
技術書典7で買わせていただいた、実践入門Kubernetes カスタムコントローラへの道の著者であられるバルゴさんによるKubernetes Controllerについての発表。
Controllerの概要から内部の実装についてまで説明されている100P超えの力作スライドです。 ReplicaSetをapplyしてからデリバリされるまでの処理を該当ソースへの参照箇所まで添えて説明してくれており開始10分でこれてよかったと思えました。
kubebuilder/controller-runtime入門 with v2 updates
kfyharukzさんによるkubebuilder v2の紹介/デモ。
kubernetesのAPIを拡張するためのSDK kubebuilderについての発表です。
Kubernetesのbuiltin Resouceの理解もまだあやしい自分にとっては発展的な内容でした。CKA合格できたらCustom Resourceにも挑戦したいです。
Kubernetes 1.16: SIG-API Machineryの変更内容
Introduction of Operator Frameworkが行われる予定でしたが、発表者の方が体調不良とのことで内容が変更になりました。
LadicleさんによるKubernetes 1.16: SIG-API Machineryの変更内容 そもそもSIGという単語がわかっていませんでした。調べてみたところKubernetes Projectの開発単位という感じでしょうか。 興味があるSIGから追いかけてみるととっかかりとしてはよいというアドバイスもいただきました。
zlab社がQiitaでKubernetesやGo関連で参考になる記事をたくさんあげてくれているのでフォローしていこうと思いました。
Kubernetes 1.16: SIG-CLI の変更内容
同じくzlab社のすぱぶらさんによるKubernetes 1.16: SIG-CLI の変更内容です。
kubectlの実践的な解説で自分が打ったことがないコマンドやオプションばかりでした。
kubectl debug
は利用できたらとても便利そうなので待ち遠しいです。
LT
ClusterAPI v1alpha1 → v1alpha2
r_takaishiさんによるClusterAPIについて。 発表資料のリンクが見つけられず。 ClusterAPIについてはまったくわかっておらず。そもそもKubernetesってCluster(特にcontroll plane)は作成されている前提だと考えていたので気になるところです。 技術書典7では買えていなかったはじめるCluster API読んで出直します。
自動化はshell-operator とともに。
nwiizoさんさんによるshell(bash)とkubernetesについて。 そもそも、operatorについてのわかっていないので、なんかbashでもkubernetesの処理にはさめるんだなくらいの理解しかできませんでした。 ここは議論のあるところだと思いますが、自分は以下の点からあまりbashを本番関連の処理に組み込みたくないと考えているのですがどうなんでしょうか。
- network処理には必ずtimeout設定したい
- error handling
- logging(structured, leveling,...)
- signal handling(gracefully shutdown, resource cleanup等)
- test書きたい
- 依存を明示
(bashでできないことはないと思うのですが上記のことやろうとすると肥大化するかscriptの手軽さが結局失われる)
自作 Controller による Secret の配布と収集 - unblee
unbleeさんによる自作 Controller による Secret の配布と収集
wantedly社でのKubernetes運用上の課題をControllerを作成して解決されたお話でした。
1-MicroService 1-Namespaceで運用されているそうです、実運用されている方々のNamespaceの切り方についてはもっとお話を伺ってみたいと思いました。
懇談会
SessionとLTの間に30分程度の懇談会の時間が設けられています。(飲食物の提供はCyberAgent社) たまたま技術書典7で買って、当日も読んでいたカスタムコントローラへの道の著者のバルゴさんが発表されていたので、本買いましたとご挨拶させていただきました。またCKA、CKADをお持ちとのことで、CKAのアドバイスも聞けました。
Ladicleさんの発表の際に用いられていたQiitaのiconどこかでみたことあるなー思っていたのですが、Software Design 2017年9月号の特集 Web技術【超】入門いま一度振り返るWebのしくみと開発方法でweb serverの実装をgoでやられている方であることを思い出しました。
go-bindata
で静的アセットファイルをgoのバイナリーに組み込むやり方をここではじめて知りました。
次回
次回は10月24日で、Kubernetes上で動かすアプリケーション開発のデバックとテストについてだそうです。 こちらも楽しみですね。
まとめ
Kubernetes Meetup Tokyoには初参加で、自分のKubernetesについての理解が、GKEにslack botをdeployしてみる程度(会社のブログで記事にしました。) でしたがとても勉強になり参加してよかったです。
せっかくなのでゼロから始めるKubernetes Controllerをおってみる
ゼロから始めるKubernetes Controllerで、ReplicaSetをapplyした際のControllerの挙動が該当コードのリンクつきで解説されているので、追えるところまでおってみました。kubernetesのversionは1.16です
kubectl apply
kubectl
でReplicaSetをapplyして、api-serverで処理されている前提です。
ReplicaSet Controller
の起動
slideでは、ReplicaSetController
がReplicaSet
が生成されたことを検知したところから解説されていますが、起動処理を簡単におってみました。
ReplicaSetController
自体は、kube-controller-manager
binaryに含まれているので、起動処理はkube-controller-manager
コマンドから始まります。
// Run runs the KubeControllerManagerOptions. This should never exit.
func Run(c *config.CompletedConfig, stopCh <-chan struct) error
func NewControllerInitializers(loopMode ControllerLoopMode) map[string]InitFunc
func StartControllers(ctx ControllerContext, startSATokenController InitFunc, controllers map[string]InitFunc, unsecuredMux *mux.PathRecorderMux) error
各controllerの起動処理を実行しているようです。 肝心のReplicaSetController
の起動処理をみてみます。
func startReplicaSetController(ctx ControllerContext) (http.Handler, bool, error)
ReplicaSetController
の生成と起動処理を別goroutineで実行しているようです。
func (workers int, stopCh <-chan struct)
指定された数のworkerを起動して、stopCh
でblockしています。
func ()
func () bool
肝心のworkerはqueueからtaskを取得して、ReplicaSetController.syncHandler()
処理を呼び出しています。 このqueueまわりもslideの後半で解説されていましたが、概要としてはapi-serverからcontrollerが関心のあるEventに絞って取得していると理解しています。
func NewBaseController(rsInformer appsinformers.ReplicaSetInformer, podInformer coreinformers.PodInformer, kubeClient clientset.Interface, burstReplicas int,
gvk schema.GroupVersionKind, metricOwnerName, queueName string, podControl controller.PodControlInterface) *ReplicaSetController
ReplicaSetController.syncHandler
にはsyncReplicaSet
が生成処理時にセットされています。
// syncReplicaSet will sync the ReplicaSet with the given key if it has had its expectations fulfilled,
// meaning it did not expect to see any more of its pods created or deleted. This function is not meant to be
// invoked concurrently with the same key.
func (key string) error
概要としては、処理対象のReplicaSet
とfilterlingしたPod
を取得して、ReplicaSetController.manageReplicas()
を呼んでいます。 これでようやくslideの最初の処理のたどり着きました。
ReplicaSetController.manageReplicas()
// manageReplicas checks and updates replicas for the given ReplicaSet.
// Does NOT modify <filteredPods>.
// It will requeue the replica set in case of an error while creating/deleting pods.
func (filteredPods []*v1.Pod, rs *apps.ReplicaSet) error
func slowStartBatch(count int, initialBatchSize int, fn func() error) (int, error)
Pod
とReplicaSet
のreplica数の差分をとって、Pod
の作成処理を実行していますね。 slowStartBatch()
は作成処理を並列で走らせるhelper関数のようです。 段階的に一度に起動するgoroutineの数を増やしていく処理の書き方として非常に参考になります。(IntMin()
のような処理はstd libで欲しいと思ってしまう) ReplicaSetController.podControl
はinterfaceで、実際のPod
作成処理はReadPodControl
が実装しています。
func (namespace string, template *v1.PodTemplateSpec, controllerObject runtime.Object, controllerRef *metav1.OwnerReference) error
func (nodeName, namespace string, template *v1.PodTemplateSpec, object runtime.Object, controllerRef *metav1.OwnerReference) error
確かにslideのとおり、r.createPods("", namespace, template, controllerObject, controllerRef)
としてnodeName
が空のPod
を生成しているのがわかります。
Schedulerがenqueue
func AddAllEventHandlers(...)
func assignedPod(pod *v1.Pod) bool
Scheduler
がpodInformer
にevent handlerを登録する際に、podがassigne(NodeName
が設定されている)されていないことを条件とするfilterを設定していることがわかります。
kubeletはskip
// NewSourceApiserver creates a config source that watches and pulls from the apiserver.
func NewSourceApiserver(c clientset.Interface, nodeName types.NodeName, updates chan<- interface)
kubelet
のapi serverへのclient生成処理時に、Pod
のHost名が(おそらく)自身のnode名と一致するFilterを設定しているようです。
Schedulerがnode nameを設定
func ()
[https://github.com/kubernetes/kubernetes/blob/2f76f5e63872a40ac08056289a6c52b4f6250154/pkg/scheduler/scheduler.go#L516](white-space:nowrap; overflow:scroll;)
func (assumed *v1.Pod, host string) error
[https://github.com/kubernetes/kubernetes/blob/2f76f5e63872a40ac08056289a6c52b4f6250154/pkg/scheduler/scheduler.go#L447](white-space:nowrap; overflow:scroll;)
Scheduling処理自体は一大Topicですが、流れとしては、なんらかの方法でNode名を選出して、Pod
のnode名に指定していることがわかります。
kubelet
がコンテナを起動
func (pod *v1.Pod, podStatus *kubecontainer.PodStatus, pullSecrets []v1.Secret, backOff *flowcontrol.Backoff) (result kubecontainer.PodSyncResult)
kubelet
の処理はまったく追えていないのですが、コンテナを起動しているような処理を実行しています。
kubelet
がPod
のstatusを更新
func (o syncPodOptions) error
Pod
のTerminating
// dispatchWork starts the asynchronous sync of the pod in a pod worker.
// If the pod is terminated, dispatchWork
func (pod *v1.Pod, syncType kubetypes.SyncPodType, mirrorPod *v1.Pod, start time.Time)
ReplicaSetController
がPod
を削除
func (filteredPods []*v1.Pod, rs *apps.ReplicaSet) error
if diff < 0 else if diff > 0
return nil
}
ここで再び、ReplicaSetController.manageReplicas()
に戻ってきました。今度は、specよりも実際のPod
が多いので、削除処理が走るようです。削除処理はシンプルに削除する数だけgoroutineを起動するようです。
Reconcile
ここまで、非常に簡単にですがslideにそって、ReplicaSetController
を中心に該当コードを追いかけてみました。 kubernetesのcodeを初めて読んだのですが、各componentの実装がだいたいどのあたりあるのかを知るためのとっかかりとして非常に参考になりました。slideの後半では、Informer
やWorkQueue
についても解説されているので、是非そちらも追いかけてみようと思います。