年中アイス

いろいろつらつら

DeploymentとServiceをyamlファイルで定義する

kubectlコマンドとオプションでnginxをminikube上で動かしました。 今回は、コマンドで起動内容を指定するのではなく、定義ファイルを使って動かすようにします。定義ファイルにすることでgitで管理できるようになります。

コマンドの振り返り

以下のように起動して、接続できるようにしまていました。

# nginxの起動
kubectl run nginx --image=nginx:1.11 --port=80

# Macから接続できるように
kubectl expose deploy nginx --name=nginx-nodeport --port=80 --target-port=80 --type="NodePort"

これは実際に何をやっているかというと、Deploymentという機能を使ってnginxコンテナを起動し、Serviceを使ってnginxコンテナにアクセスできるようにしています。

Deployment

Deploymentは、複数のコンテナを並列起動し、世代管理できる仕組みです。今回Deployment(+ReplicaSet, Pod)自体が何かというのはあまり重要ではないので省略。以下の記事で細かく解説されています。

qiita.com

Service

Serviceは複数のコンテナへのアクセスを仲介してくれるロードバランサーです。個々のコンテナのアクセス方法を把握しなくても、Serviceの受付口だけ知っていれば、通信できます。

定義ファイル(yaml)にする

定義ファイルはJSONyaml形式が使えます。他のプログラムを仲介する場合はJSONが良さそうですが、設定管理なら個人的にはyamlが好きです。(コメントアウトやコメント書ける点が良い)

nginx-deploy.yml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 2
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.11
        ports:
        - containerPort: 80

kubectl runで指定していたもの+を定義します。

プロパティ 説明
apiVersion Deploymentはベータ開発中なので、extentions/v1betaだそうです *1
kind kubectl runで動かしていたので、隠れていましたが、実態はDeploymentなので明示します。
metadata.name kubectl runの後に指定していた名前
spec.replicas --replicasオプションで指定できる、レプリカ数(コンテナの並列数)
spec.template.
metadata.labels
識別するための任意のKeyValue
spec.template.spec.
containers.name
コンテナの名前
spec.template.spec.
containers.image
--imageオプションで指定していたコンテナイメージ
spec.template.spec.
containers.ports.
containerPort
--portオプションで指定したコンテナの公開しているポート

続いてSerivce。kubectl exposeで指定したもの+を定義します

service.yml

apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport
spec:
  type: NodePort
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: nginx
プロパティ 説明
apiVersion ServiceはDeploymentと異なりv1です。
kind 同様にkubectl exposeを使っていましたがServiceを明示します。
metadata.name --nameオプションで指定していたもの
spec.type --typeオプションで指定していたもの
spec.ports.port --portで指定したいたもの
spec.ports.protocol TCPを明示
spec.ports.targetPort --target-portで指定していたコンテナに対するポート
spec.selector 前述のDeploymentのlabelと関係します。後で詳しく。

起動

kubectl createコマンドで作成(起動)します。

kubectl create -f nginx-deployment.yml
kubectl create -f service.yml

-fは同時に複数指定も可能です。

kubectl create -f nginx-deployment.yml -f service.yml

minikube経由でブラウザ起動して確認。nginxのwelcomeページが見れます。

minikube service nginx-nodeport

DeploymentのlabelとServiceのselector

kubectl exposeコマンドは、その後にdeploy nginxと指定していました。これはnginxという名前 のdeploymentをターゲットにするという意味です。定義ファイルの場合は、labelとselectorで紐付けが行われています。

Serviceのselectorで指定したkey:valueと一致するDeployment*2に、リクエストを流すようになります。 run: nginxを指定していますが、特にrunというkeyにしなくても、Deploymentのlabelをapp: httpserverにして、Serviceのselectorも同様に指定することでもリクエストが流れます。一致すればOKです。

Deployment以外にもlabelやselectorを書けるので、nameよりも柔軟に対象を決めることができるようです。

Labels and Selectors | Kubernetes

いろいろなところで、deploy nginxなど、いちいち名前を書いてられないので、labelをつけて、複数のターゲットを同一label名で識別できるようにすることを目的としているようです。でもlabelは多分もうちょっと詳しく調べないとよくわからず。

参考

*1:http://stackoverflow.com/questions/38547229/apiversion-and-beta-versions

*2:DeploymentじゃなくReplicaSetかもしれない?

Linuxでメモリ使用量が増え続けた

AmazonLinux 2017.03にnginx乗せて稼働させてたら、なぜかメモリ使用量が、1日ちょっとで2GB後半にさしかかりました。cacheではなくusedを徐々に消費してたので、これは何かリークしてる疑い。

プロセス等を見てもメモリを使っているものもいないし、疑いのあるプロセスをrestartしても改善しませんでした。

何だろうなーと調べてみたらすぐ出てきました。特にAmazonLinuxは関係なし。

dev.classmethod.jp

上記ページと同じく、NSSの問題で、curlがdentryというディレクトリ階層構造の管理をしているキャッシュを多く消費してしまうと。curlhttpsの監視が動いており、それが5分に1回なので、徐々にリークした様子。1時間に100MB程度ずつ増加していたようです。

回避策は、NSS_SDB_USE_CACHE=YESという環境変数を指定すること。とりあえず監視スクリプトexport NSS_SDB_USE_CACHE=YESを追加したら、増加が止まりました。

溜まったキャッシュは、以下のようにして解放されました。

echo 2 > /proc/sys/vm/drop_caches

>>でも>でもどっち動きますが多分>の方が適切?2という値は対象のキャッシュによって異なります。

クリアする対象キャッシュ
1 ページキャッシュ
2 dentry,inode
3 ページキャッシュ,dentry,inode

まとめ

じわじわ増えてく系のメモリリークは怖いです。調べたらたくさん出てきたので、割とメジャーな要因みたいですね。

Slabは知らなかったので調べてみたら、ざっくり言うとカーネル側のキャッシュとのこと。細かいメモリ周りはやっぱよくわかってない感。

参考

minikubeで自分の作ったimageを使う

前回minikubeの実行環境を作りました。公開されているnginxのimageを使いましたが、実際は自分でimageを作成し、それを実行させることがほとんどだと思います。minikubeはdockerを内包しているので、そこでdocker buildすればimageが登録され、使うことができます。

nginxに静的ページを追加したコンテナを作って試す

まず、minikubeのdockerを使うために以下を実行します。

eval $(minikube docker-env)

次にお試し用のpage.htmlとDockerfileを作ります。

# page.html
echo '<html>
  <head><title>this is page</title></head>
  <body>original page</body>
</html>' > page.html

# Dockerfile 
echo 'FROM nginx:1.11

COPY page.html /usr/share/nginx/html/page.html' > Dockerfile

ファイル構成としてはこんな形になります。

k8s/  ・・・名前はなんでもよくここにいる状態でeval $(minikube docker-env)
  |- Dockerfile
  +- page.html

imageを作ります。タグはlatestだと動かないので、適当にバージョンつけます。

docker build -t example/nginxpage:0.1.0 .

k8sで動かします。

# コンテナ起動
kubectl run nginxpage --image=example/nginxpage:0.1.0 --port=80

# Macからアクセスできるように
kubectl expose deploy nginxpage --name=nginxpage-nodeport --type="NodePort"

ブラウザで確認します。

minikube service nginxpage-nodeport

標準ブラウザが立ち上がり、nginxのwelcomeページが表示されるので、URL欄に/page.htmlを追加します。 そうすると、original pageと表示され、自分で作ったコンテナが利用できていることがわかります。

参考