decadence

個人のメモ帳

docker, fig, k8sで遊ぶ

どう考えても異常に便利だし、どう見ても流行ってるし、2015年になる前に現状に追いつきたい
先人の知見を基に単に試すだけで新しいことは何もしてない

  • やる前の状態
    • dockerがlinuxカーネルの上にコンテナとして動いて、その辺の機能使って良い感じに軽量なコンテナとして使えるって思ってる
    • Docker入門: コンテナ型仮想化技術の仕組みと使い方 の13枚目とか理解してる
    • figはコンテナを複数個動かしたりするのに役立ってKubernetes(k8s)がdockerを使う複数個のホストを管理するのに役立つやつって勝手に思ってる
    • 他人が用意してくれたDockerfile使ってbuildしてrunしたの使ったことがある
    • OSX上で動かすんだけど、そのためにはboot2dockerとか必要って知ってる

そういえばMesosやMarathonとかもあったけど、全てdockerコンテナで動かすって仮定すればk8sで賄えるって感じなんだろうか

  • 目標はこのへんを適当に触ってある程度概念とか理解出来たら良い
    • dockerの基本を学ぶ: (1個のホストと)1個のコンテナ
    • fig -> docker って感じで複数個のdockerいじりつつ通信とかさせる: 1個のホストと複数個のコンテナ
    • kubernetes も合わせて触りたい: 複数個のホストと複数個のコンテナ
      • serfとかconsulで管理したりはしない

はじめの環境(後で変わるかも?)

  • boot2dockerでやる
    • boo2docker shellinitで初期設定とか済ませておく
  • docker pull ubuntu:latestしてubuntuのimageで最初は始める

dockerコマンドの基本

全部docker help <command>に書いてるし、↓の試した
(ドキュメントもあるけどhelpで十分過ぎる)

  • docker run : コマンドを実行
    • -i: interactive
    • -t: tty
    • --rm: 実行後に消す
    • --name: 名前つける
    • -d: daemonとして実行detachだった(backgroundで実行みたいな感じ)
  • docker rm <container_id>: コンテナ消す
  • docker ps
    • -a: all
    • -l: latest
    • -f: filter
    • -q: container id だけ出す
  • docker commit <container_id>: 止まってるコンテナとか指定して現状のimageとして保存する
    • docker run -ti ubuntu /bin/bash
    • > apt-get -y update && apt-get install -y golang && exit
    • docker commit $(docker os -ql) snapshot/golang
  • docker images: image一覧
  • docker rmi : image消す
  • docker attach, detach, start, stop, logs,...

  • run --rmしないとstatus=exitedなコンテナが残りまくる

  • 掃除: docker rm $(docker ps -aq -f=status=exited)

普通に触る分にはこれぐらい

  • 色々進めてく中でこの辺のコマンドやオプションも覚えたから追記する
    • docker inspect <container_id>: ipaddressとか色んな情報見れる
    • docker run --net=<bridge|...> ...
      • 通常dockerはdocker0って仮想ブリッジを通してコンテナ毎にinteraceを作ってく
      • これがnet=bridgeのデフォルト挙動で、その辺を変えたり出来る
    • docker run --link <container>:<alias> ...: 他のコンテナとリンクさせる
    • docker port <container_id> <port>: ipやポートフォワードの情報

Dockerfile

定義方法

ドキュメント Dockerfile - Docker Documentation
Dockerfileに作りたいimageのレシピみたいのを書く
作ったDockerfileはDocker Hubリポジトリとして置けて、ここに色んな公式Dockerfileとかもある

  • FROM <image> org FROM <image>:<tag>
  • MAINTAINER <name>
  • RUN <command>: buildする時に実行されるやつ
    • 引数ある時: RUN ["command", "arg"]
  • EXPOSE <port>: コンテナ内部から見たポート番号を指定して開放
  • ENV <key> <value>: 環境変数
  • ADD <src> <dest>: コンテナの中に外のファイルをコピーする
    • urlが指定できる・圧縮ファイルが自動解凍される
  • COPY <src> <dest>: コンテナの中に外のファイルをコピーする
    • urlが指定できない・圧縮ファイルが自動解凍されない
  • CMD <command>: コンテナ起動時に実行される
  • ENTRYPOINT <command>: コンテナ起動時に実行される
    • docker runの引数をパラメータとして扱う
  • VOLUME ["/data"]: 外部からボリュームとしてマウントするディレクトリ
  • USER <name>: コンテナ起動時のユーザ名
  • WORKDIR <dir>: CMDが実行されるディレクトリを指定
  • ONBUILD <instruction>: build完了後のhook

【翻訳】いいDockerイメージを構築するには? ーDockerfileのベストプラクティスにもあるけど、build toolとか必要最低限に抑えつつ、RUNのコマンドは繋げれるものはつなげた方が良いっぽい

適当に公式のdocker-nginx/Dockerfile · nginxinc/docker-nginx持ってくると、まぁ全部読める
ポイントとしては、RUN apt-get installには-yをつけたり、上のベストプラクティスにもあるように、必要なくなったファイルを消すとか
devian:wheezy(debian Repository | Docker Hub Registry - Repositories of Docker Images)を最初に指定して、ここから積んでくってイメージ勝手に持ってる

FROM debian:wheezy
MAINTAINER NGINX Docker Maintainers "docker-maint@nginx.com"
RUN apt-key adv --keyserver pgp.mit.edu --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62
RUN echo "deb http://nginx.org/packages/mainline/debian/ wheezy nginx" >> /etc/apt/sources.list
ENV NGINX_VERSION 1.7.8-1~wheezy
RUN apt-get update && apt-get install -y nginx=${NGINX_VERSION} && rm -rf /var/lib/apt/lists/*
# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log
RUN ln -sf /dev/stderr /var/log/nginx/error.log
VOLUME ["/var/cache/nginx"]
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]

そういえばdocker run-e --env``-u --user,-v --volume,-w --workdirオプションがある
外部にnginxのログを置きたい場合には上記ログ系の設定を除きつつdocker run -v /tmp/nginx_log:/var/log/nginx nginx_imageのようにすれば良い

Dockerfileを試す

  • ubuntuにnginxを乗っけてみる(普通にapt-getして入れる)
    以下のようなDockerfileを用意してdocker build -t snapshot/nginx .でimageを作成
    nginxはデフォルトでデーモンになるので、ならないように実行しておく
FROM ubuntu:latest
RUN apt-get update && apt-get install -y nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
  • docker imagessnapshot/nginxがあることを確認
  • docker run -d -p 80:80 snapshot/nginx
    • -pは外側のポートと内側のポートをforwarding
  • docker psでnginxのコンテナが動き続けてるはず
  • curl http://localhost/とかするとnginxのレスポンスが得られたから成功

docker stop $(docker ps -ql)docker rm $(docker ps -aq -f=status=exited)とか、help見なくても打てるようになったのも成功

fig

Dockerfileを基にimageさえ出来てしまえばコンテナの環境は万全の状態になってるはず
でも実際はその上に何かしらのサービスを動かしたりするんだけど、どこのポートを繋いだり、どうやって起動するのかってのをまとめて実行させたりってのをfigが全てラップしてくれたりする?
docker自体に--linkって他のコンテナとリンクする機能があるんだけど、その関連も勝手にfig.ymlに書いといたらやってくれるのが良さそう
ちなみにmotemen/github-issue-badgeって超便利なのがあるんだけど、ここにもDockerfilefig.ymlが用意されてるから、fig upですぐ動くものが手に入る(これHerokuのdeployボタンもあるしすごい)

Fig | Fast, isolated development environments using Docker が普通に良さそうだからこれに従って試してみる

  • OSX上で動かしたいんでsudo pip install -U figでインストール
    • なんか色々警告出たけどfig --version出来るしスルー
  • figの場合ヘルプはfig -horfig --help

fig.ymlの定義方法

fig.ymlの定義方法を見たら、どういう概念があるとかも分かる気がする
↓で試したfig.yml見ながら確認、どうやらYAMLのトップがサービス名で、サービス毎の設定を書く感じっぽい

  • image: dockerのimageを指定
    • アプリには手元にDockerfileを使って、DBとかには外のimageを持ってくるとか
  • build: Dockerfileのあるディレクトリを指定
  • command: アプリの起動などのデフォルトコマンド
  • links: 他のサービスとリンクする
    • サービス名やエイリアス(SERVICE:ALIAS)が指定可能
    • エイリアス/etc/hostsで同じipが指定される
    • 上で書いて無かったけどdocker runのオプションにも--link <container>:<alias>ってのがある
  • ports: 開放するポート及び、ポートフォワード
    • HOST:CONTAINER
    • YAMLの都合上、文字列で指定するのが望ましい
  • expose: linkされているサービスのみ用いることが出来るportを指定
  • volumes: 外部からボリュームをマウントさせる際のパスを指定
    • HOST:CONTAINERや、HOST:CONTAINER:roroはアクセスモード)と指定
  • volumes_from: 他のサービスを指定してボリュームをマウントさせる
  • environment: 環境変数を配列でもディクショナリでも指定出来る
    • key: valueみたいなディクショナリをenvironment:の下に書くとかそういう感じ
  • net: ネットワークモード?docker--netと同じ値を用いるらしい
    • docker runのオプションに--netってのがあるらしい、DockerのHost networking機能 | SOTAからそのまま引用するけど、この記事読んだ方が良い
      • --net=bridge:仮想ブリッジdocker0に対して新しくネットワークスタックを作成する(default)
      • --net=container:<コンテナ名|コンテナID>:他のコンテナのネットワークスタックを再利用する
      • --net=host:ホストのネットワークスタックをコンテナ内で利用する
      • --net=none:ネットワークスタックを作成しない
    • dockerのネットネットワークはホストのdocker0って仮想ブリッジにvethのインターフェースを通して、IPマスカレード(ipやportを変換)した上えでコンテナのeth0に繋がる
  • dns: DNSサーバを指定出来る(8.8.8.8とか)
  • その他: docker runのオプションと同じ事出来るってさ
    • working_dir, entrypoint, user, hostname, domainname, mem_limit, privileged

netのとこで思わずdockerについてのネットワーク周りを学べてしまった
Dockerのネットワークの基礎 | SOTA とか良かった

試す

試したいけどそういえばコマンドを確認してないから軽く触れる

  • コマンドが複数個あって、ドキュメントもある
  • 大体のコマンドが予想出来そうなものばかりだけど、迷いそうなのとか面白いのだけ書く
    • build: サービス名に対して、buildする -> からのrun
    • scale: サービス毎に、何個のコンテナを起動するのかを指定出来る
    • up: サービスに対して(re)build, create, start, attachするってさ

公式に乗ってるサンプルから1個試す
Flaskのサンプルは普通にRedisとか使う感じでまぁ十分figの利点が分かりそう

  • Dockerfile: まぁ分かる
  • fig.yml: 同じの使うけど確認する
    • redisとwebってサービスを用意する、これらはもちろん別のコンテナに乗る
    • redisは(手元にあったら別だけど)外部のredisってimageを使って、webはbuildを指定してるから手元のDockerfileからimageを作る
    • webサービスがredisを使うから、linksでつなぐ
web:
  build: .
  command: python app.py
  ports:
    - "5000:5000"
  volumes:
    - .:/code
  links:
    - redis
redis:
  image: redis

後はfig up -dとかすると、5000のポートを叩くとアクセス出来る(boot2docker ipした先に)

  • figは勝手に現在のディレクトリ名を使ってworkdir_webworkdir_redisってimageを作る
  • fig run webみたいなアクセスが出来るから、設定をYAMLに書いてさえしまえば、dockerってコマンドがいらなくなる感じで良い
  • fig run web cat /etc/hostsみたいなのすると、コンテナの中でredisとどう繋がってるが見える
  • ホスト側からはdocker inspect $(docker ps -lq)とかするとweb版の詳細が見れる
  • redis側設定のNetworkSettings.IPAddressの値と中から見た/etc/hostsの中身が同じである事が確認出来る

複数個のコンテナを使う場合にfigはdockerの機能をラップしてくれて便利って感じだ(1個でも"fig upしろ"って言えるから便利だけど)

Kubernetes(k8s)

dockerの基本をやって、figで上手いこと複数個のコンテナを動かす方法を学んだし、最後はk8sで複数個のコンテナを動かすホストを複数個...みたいのをしてみたい
どうでもいいけどkubernetesってe多いな

構成

kubernetes/DESIGN.md at master · GoogleCloudPlatform/kubernetes
Monitoring Kubernetes - Hatena Developer Blog

  • ks8は分散マイクロサービスのような複数個のコンテナを扱うアプリケーションのためのもの
  • Master(Minionを制御するやつ)とMinion(様々なコンテナが入ってるやつ)がいる
    • Masterはcliで叩くREST APIを提供している
    • 分散ストレージを操作するためのスケジューラもMasterに存在
  • MinionはMasterに対するNodeとなり、そのの中でdockerが動いてて <=> Host?
  • その中にkubelet、cAdvisor、proxyがあって
    • kubelet <- このへんが大事
      • The Kubelet is the logical successor (and rewritten in go) of the Container Agent that is part of the Compute Engine image
      • kubeletはyamlで書かれたマニフェストから設定を読み込む
      • マニフェストはファイル、URL、etcd等から指定でき、20秒毎などにチェックされたりする
      • 設定をもとに、podをどのようにして起動したりするのかを管理する?
    • cAdvisor <- このへんも大事らしい
  • proxyからさらに中に複数個あるpodに飛ばす
    • 同一のMinionの上で同じようにスケジューリングされるべきコンテナの集まりがpod
  • podには複数のラベルを付けることが出来る(key=value)
  • ...

後はYAML書いて、k8sが用意したcli叩くだけって感じで試せそう

試す

Getting Started - kubernetesにGCE、AWS、CloudStack使ったりするサンプルがあるけど、雑に試せたら良いから適当なの選ぶ

予め用意されたVagrantを使って試す
  • Vagrant上でやるのが安定な気がする(これでパッと試して雰囲気感じて終わって良いという気持ち)
  • releasesのページからkubernetes落としてきて、そこにあるVagrantfileをそのままつかう
  • このVagrantを使うとデフォルトではMasterが1台あって、Minionが3台立ち上がるようになっている
    • vagrant upするだけで複数台のホスト立ち上がるしprovisionも用意されたのが勝手に走る
    • 予めMasterとMinionそれぞれのprivate_network内でのipアドレスは固定してある
  • vagrant ssh masterしてsystemctl -a | grep kubeの結果下の3つのサービスが見つかる
kube-apiserver.service          loaded    active   running   Kubernetes API Server
kube-controller-manager.service loaded    active   running   Kubernetes Controller Manager
kube-scheduler.service          loaded    active   running   Kubernetes Scheduler Plugin
  • systemctrl status <>すると各々こんな感じで立ち上げられてる事がわかる
    • kube-apiserver:
    • kube-controller-manager:
    • /usr/local/bin/kube-scheduler -master=127.0.0.1:8080
  • 同様にvagrant ssh minion-1をしてsystemctl -a | grep kubeするとこんな感じ
kube-proxy.service loaded    active   running   Kubernetes Kube-Proxy Server
kubelet.service    loaded    active   running   Kubernetes Kubelet Server

クラスタ操作のためのコマンド

  • ./cluster/kube-[up|down].shクラスタを立ち上げたり落としたり出来る
  • ./cluster/kube-push.shで新しい更新内容をクラスタに反映出来る
    • vagrantの場合、vagrant provisionするだけ
  • ./cluster/kube-cfg.shは上で書いたけどRESTAPI叩くやつ
  • ./cluster/kube-ctl.shkubectl controls the Kubernetes cluster managerって書いてるな
    • 設定ファイルを更新したりproxyを動かしたり出来るっぽい
一から作ってみる的な?

kubernetes/README.md at master · GoogleCloudPlatform/kubernetes

もうやる気なくなったのでやめた

追記

docker の新機能であるmachine, swarm, composeについても触ろうと思ってたけど↓の辺で大体分かったからもういいや