LoginSignup
3

More than 3 years have passed since last update.

Docker が動作しているホストのHostnameを表示するNginxコンテナ

Posted at

はじめに

Kubernetesで作業をしているときに、ブラウザで接続しているコンテナは、どのWorkerで動いているのか気になったため作成しました。
Workerをわざと停止して、接続先を確認する時に使っています。

動作確認した環境

  • Raspberry Pi 4
  • Ubuntu 20.04
  • Docker 19.03.13

イメージ

https://hub.docker.com/r/yasthon/nginx-display-hostname にアップしています。

動かしてみる

ここでは、ホスト名「dockerhost.example.jp」の環境で実行しています。

$ docker pull yasthon/nginx-display-hostname
$ docker container run -d -v /etc/hostname:/usr/share/nginx/html/hostname -p 80:80 yasthon/nginx-display-hostname
$ curl http://localhost/index.sh
<html><head>
<title>dockerhost.example.jp</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head><body>
HOSTNAME : dockerhost.example.jp
</body></html>

ブラウザからも確認します。
http://[DockerホストのIPアドレス]/index.shにアクセスします。

HOSTNAME : dockerhost.example.jp

動作

コンテナの起動時に/etc/hostname をmountしています。
Nginxからshを動かして、hostnameを読んでいます。

Dockerfile

ローカルでビルドする時に使うファイルです。

Dockerfile
FROM debian:buster-slim

COPY default.conf /etc/nginx/conf.d/

COPY index.sh /usr/share/nginx/html/

RUN apt-get update && \
  apt-get install -y --no-install-recommends nginx fcgiwrap && \
  apt-get autoclean && \
  rm -rf /var/lib/apt/lists/* && \
  echo "daemon off;" >> /etc/nginx/nginx.conf && \
  rm -f /etc/nginx/sites-enabled/default && \
  chmod 744 /usr/share/nginx/html/index.sh && \
  chown www-data:www-data /usr/share/nginx/html/index.sh

CMD /etc/init.d/fcgiwrap start && nginx

普通にOSへインストールした時は簡単に動作したのに、コンテナで実行したら問題が発生しました。

  • Nginxのdefault rootは/usr/share/nginx/html/だと思いこんでいたら、/var/www/htmlを参照していました。コンテナの用途が限定的なので、調査はせずに/etc/nginx/sites-enabled/defaultを削除することで解決しました。
  • fcgiwrap.socketが無かったです。CMDに /etc/init.d/fcgiwrap startを追加してコンテナ起動時に作成しています。
  • permissionエラーでました。chmodchownを追加しました。
  • DockerHubからpullしたNginx Official イメージでは、思うように動作できなかったです。パッケージでインストールを行い動作させました。

default.conf

Nginxの設定ファイルです。

default.conf
server {
  listen       80;
  server_name  localhost;
  location ~ \.sh$ {
    root   /usr/share/nginx/html/;
    include           /etc/nginx/fastcgi_params;
    fastcgi_index     index.sh;
    fastcgi_param     SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_pass      unix:/var/run/fcgiwrap.socket;
  }
}

Dockerfile に比べて、何の問題もなく。

index.sh

mountしたhostnameファイルを読み込んで表示します。

index.sh
#!/bin/sh

host_name=$(cat hostname)

echo "Content-type:text/html"
echo ""
echo "<html><head>"
echo "<title>${host_name}</title>"
echo '<meta http-equiv="Content-type" content="text/html;charset=UTF-8">'
echo "</head><body>"
echo "HOSTNAME : ${host_name}"
echo "</body></html>"

同じく、何の問題もなく。

ローカルでビルドする

イメージ名を「nginx-display-hostname」にしています。
3つのファイルを同じディレクトリに置いて、docker buildを実行します。

$ docker image build -t nginx-display-hostname .
$ docker container run -d -v /etc/hostname:/usr/share/nginx/html/hostname -p 80:80 nginx-display-hostname
$ curl http://localhost/index.sh
<html><head>
<title>dockerhost.example.jp</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head><body>
HOSTNAME : dockerhost.example.jp
</body></html>

ブラウザからも確認します。
http://[DockerホストのIPアドレス]/index.shにアクセスします。

HOSTNAME : dockerhost.example.jp

Kubernetes上での動作

volumeMountsとvolumesを使用して、/etc/hostnameをmountする必要があります。

sample.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: nginx-prod # namespace の名前
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment # deployment の名前(replicaset の名前もこれになる)
  namespace: nginx-prod # namespace の名前
spec:
  selector:
    matchLabels: # ラベルがマッチしたPodを対象とするreplicasetの作成
      app: nginx-pod
  replicas: 2
  template: # Pod のテンプレート
    metadata:
      name: nginx-pod # Pod の名前
      namespace: nginx-prod # Pod のnamespace の名前
      labels: # Pod のラベル
        app: nginx-pod
    spec:
      containers: # コンテナの設定
        - name: nginx-container # コンテナの名前
          image: yasthon/nginx-display-hostname # イメージの名前
          env:
            - name: nginx-container
          ports:
            - containerPort: 80 # コンテナのポート
          volumeMounts:
            - name: file-hostname
              mountPath: /usr/share/nginx/html/hostname
      volumes:
        - name: file-hostname
          hostPath:
            path: /etc/hostname

Podを起動します。

$ kubectl apply -f sample.yaml
namespace/nginx-prod created
deployment.apps/nginx-deployment created

Podの名前を確認します。

$ kubectl get all -n nginx-prod
NAME                                    READY   STATUS    RESTARTS   AGE
pod/nginx-deployment-7ff4cc65cd-6r4qv   1/1     Running   0          3m52s
pod/nginx-deployment-7ff4cc65cd-djm9r   1/1     Running   0          3m52s

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deployment   2/2     2            2           3m53s

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-deployment-7ff4cc65cd   2         2         2       3m53s

Podの詳細情報でIPを確認します。

$ kubectl describe pod/nginx-deployment-7ff4cc65cd-djm9r -n nginx-prod | grep ^IP:
IP:           10.244.1.5

Worker上から、確認したIPへアクセスします。

$ curl http://10.244.1.5/index.sh
<html><head>
<title>worker.example.jp</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head><body>
HOSTNAME : worker.example.jp
</body></html>

Pod(nginx-deployment-7ff4cc65cd-6r4qv)は、ホスト worker.example.jp で起動していることが確認できました。
クラスター外からブラウザでアクセスする場合は、Serviceが必要になります。

最後に

すぐに作れるだろう思い作り始めたのですが、予想外に時間がかかりました。
必要としている方のお役に立てれば幸いです。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3