コンテナ間通信の設定をkubernetesとdocker-composeで同じ構成で構築してみた(nginx <-> uWSGI <-> Flask)
kubernetesでコンテナ間の通信を設定する方法の勉強のために、同じ環境をkubernetesとdocker-composeの両方で構築してみました。
環境
クライアント/サーバ
クライアント
ソフト | バージョン |
---|---|
OS | Ubuntu 20.04 LTS (Windows 10のWSL2で構築) |
docker | 19.03.12 |
docker-compose | 1.26.2 |
kubectl | 1.18.6 |
サーバ
ソフト | バージョン |
---|---|
OS | Ubuntu 20.04 LTS |
docker | 19.03.12 |
kubernetes | 1.18.6 |
kubernetes環境はkubeadmでシングルノード構成です。
※コントロールプレーンにデプロイできる設定
kubeadmでkubernetes環境構築する方法については、以下の記事を参考にして下さい。
アプリケーション構成
アプリケーションはpythonのFlaskで「Hello world」と表示するだけのシンプルなものとし、uWSGIを経由しnginxで公開するようにしました。
コンテナ構成
2つのコンテナで構成
コンテナ名 | 内容 |
---|---|
kube-test-nginx | 1) alpineのnginxコンテナを利用 2) 設定ファイル(default.conf)でkube-test-appへ接続 3) ポート番号:80 |
kube-test-app | 1) Flaskでルート(/)にアクセスされた場合に「Hello World」と表示する 2) uWSGIでhttpで公開(socketではない) 3) ポート番号:5000 |
プロジェクトのファイル構成
プロジェクト全体のディレクトリとファイルの構成です。
/kube-test
├── app ・・・Flaskアプリ
│ ├── main.py
│ ├── requirements.txt
│ └── uwsgi.ini
│
├── docker
│ ├── app
│ │ └── Dockerfile ・・・kube-test-appコンテナ
│ └── nginx
│ └── Dockerfile ・・・kube-test-nginxコンテナ
│
├── docker-compose.yml ・・・docker-compose
│
├── kube
│ └── kube-test.yml ・・・kubernetes
│
└── nginx
└── default.conf ・・・kube-test-appへの接続設定
アプリケーションを作成する
kube-test-app(Flask App)
main.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello World"
if __name__ == '__main__':
app.run()
requirements.txt
Flask==1.1.1
uWSGI==2.0.18
uwsgi.ini
[uwsgi]
wsgi-file = main.py
callable = app
master = true
processes = 1
http = :5000
chmod-socket = 666
vacuum = true
die-on-term = true
py-autoreload = 1
httpプロトコルでポート番号を5000に設定します。
kube-test-nginx (nginx)
default.conf
server {
listen 80;
charset utf-8;
location / {
proxy_pass http://kube-test-app:5000;
}
}
nginxの /etc/nginx/nginx.conf は /etc/nginx/conf.d/ ディレクトリの *.conf ファイルをインクルードするようになっていますので、ルート(/)でアクセスされた場合の転送先設定のみ記載した default.conf を作成します。
転送先のホスト名にFlaskアプリの kube-test-app の5000番ポートを指定しておきます。
Dockerfileを作成する
Dockerfile (kube-test-app)
FROM python:3
WORKDIR /app
RUN apt-get update
RUN apt-get -y install locales && \
localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8 \
LANGUAGE ja_JP:ja \
LC_ALL ja_JP.UTF-8 \
TZ JST-9
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools
COPY ./app/* /app/
RUN pip install --trusted-host pypi.python.org -r /app/requirements.txt
CMD ["uwsgi", "--ini", "/app/uwsgi.ini"]
COPYコマンドが ./app/* /app/ となっているのは、プロジェクトのルートディレクトリから実行されることを想定しているためです。
Dockerfile (kube-test-nginx)
FROM nginx:alpine
COPY ./nginx/default.conf /etc/nginx/conf.d/
CMD ["nginx", "-g", "daemon off;", "-c", "/etc/nginx/nginx.conf"]
docker-composeで構築する場合
docker-compose.yml
version: "3.2"
services:
kube-test-nginx:
build:
context: .
dockerfile: ./docker/nginx/Dockerfile
container_name: kube-test-nginx
ports:
- "80:80"
depends_on:
- kube-test-app
networks:
- my_network
kube-test-app:
restart: always
build:
context: .
dockerfile: ./docker/app/Dockerfile
ports:
- "5000:5000"
container_name: kube-test-app
working_dir: /app/
tty: true
volumes:
- ./app:/app
networks:
- my_network
networks:
my_network:
driver: bridge
docker-composeでコンテナ間で通信する場合は以下の手順で Dockerfile を作成します。
- networkを作成する(ここでは my_network )
- 通信したいコンテナを my_network 上に作成する
- 同じnetwork上のコンテナはサービス名( kube-test-app や kute-test-nginx )で通信できるようになる
- kube-test-nginx から kube-test-app に通信したい場合、 depends_on で kube-test-app を指定する
docker-composeコマンドでデプロイ
以下のコマンドで初回であればコンテナのビルドも同時に実行されます。
プロジェクトのルートディレクトリで実行します。(docker-compose.ymlファイルがある場所)
$ docker-compose up -d
アプリケーションやDockerfileを修正し、キャッシュなしで再ビルドしたい場合は、以下のコマンドでビルドを行った後に、上記のコマンドで起動すると最新の状態で実行できます。
$ docker-compose build --no-cache
実行結果確認
docker-compose ps コマンドでStateがUpとなっていることを確認します。
$ docker-compose ps
Name Command State Ports
---------------------------------------------------------------------------------
kube-test-app uwsgi --ini /app/uwsgi.ini Up 0.0.0.0:5000->5000/tcp
kube-test-nginx /docker-entrypoint.sh ngin ... Up 0.0.0.0:80->80/tcp
ブラウザから http://127.0.0.1/ にアクセスすると「Hello World」と表示ます。
kubernetesで構築する場合
docker imageをdockerhubへpush
kubernetesでのデプロイ時にDocker Hubからコンテナイメージを取得するようにしたいので、事前にDocker Hubへコンテナイメージを登録しておきます。
Docker Hubのアカウントを持っていない方は以下の記事を参考にしてみて下さい。
Docker Hubのアカウントの準備ができれば、Dockerイメージの作成とDocker Hubへイメージを登録します。
Docker Hubへログインしていない場合は、以下のコマンドでログインを済ませておきます。
$ docker login
では、 kube-test-app コンテナから始めます。
$ docker build --no-cache -t [dockerhub_account]/kube-test-app:1.0.0 -f ./docker/app/Dockerfile .
$ docker push [dockerhub_account]/kube-test-app:1.0.0
ビルド時に -t オプション で
[Docker Hubのアカウント]/[コンテナ名(kube-test-app)]:[タグ(バージョンなど。今回は1.0.0を指定)]
を指定します。
また、実行はプロジェクトのルートディレクトリから行います。
同様の手順で kube-test-nginx コンテナについても行います。
$ docker build --no-cache -t [dockerhub_account]/kube-test-nginx:1.0.0 -f ./docker/app/Dockerfile .
$ docker push [dockerhub_account]/kube-test-nginx:1.0.0
実際にDocker Hubにアクセスして2つのコンテナイメージが登録されているか確認してみましょう。
kube-test.yml
docker-composeでいうところの、docker-compose.ymlファイルの該当するファイルを作成します。
kube-test.ymlファイルを以下の全体イメージに沿って作成していきます。
コンテナ毎にServiceとDeploymentを分けて4つのYAMLファイルを作成してもよいですし、以下のように1つにまとめて記述することも可能です。
apiVersion: v1
kind: Service
metadata:
name: kube-test-nginx
labels:
app: kube-test-nginx
spec:
type: NodePort
ports:
- name: http-port
protocol: TCP
port: 80
targetPort: 80
nodePort: 30081
selector:
app: kube-test-nginx
---
apiVersion: v1
kind: Service
metadata:
name: kube-test-app
labels:
app: kube-test-app
spec:
type: ClusterIP
ports:
- name: http-port
protocol: TCP
port: 5000
targetPort: 5000
selector:
app: kube-test-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kube-test-nginx
spec:
selector:
matchLabels:
app: kube-test-nginx
replicas: 1
template:
metadata:
labels:
app: kube-test-nginx
spec:
containers:
- name: kube-test-nginx
image: [dockerhub_account]/kube-test-nginx:1.0.0
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kube-test-app
spec:
selector:
matchLabels:
app: kube-test-app
replicas: 1
template:
metadata:
labels:
app: kube-test-app
spec:
containers:
- name: kube-test-app
image: [dockerhub_account]/kube-test-app:1.0.0
ports:
- containerPort: 5000
kubectlコマンドでデプロイ
kube-test.ymlを利用してkubectlコマンドでデプロイします。
今回は、kubeディレクトリにkube-test.ymlファイルを作成しているので、kubeディレクトリで実行しています。
kubectl applyコマンドを利用すると新規デプロイ時も変更時も対応できるので便利です。
$ cd kube
$ kubectl apply -f kube-test.yml
service/kube-test-nginx created
service/kube-test-app created
deployment.apps/kube-test-nginx created
deployment.apps/kube-test-app created
実行結果確認
kubectl get all コマンドや kubectl get pod コマンドなどで確認するとPodが実行されているか確認できます。(StatusがRunningになっているかどうか)
以下は、 kube get all コマンドの実行結果です。
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/kube-test-app-bf6f459f-7wt42 1/1 Running 0 3m21s
pod/kube-test-nginx-6ffff769b5-rhg5g 1/1 Running 0 3m22s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kube-test-app ClusterIP 10.104.185.76 <none> 5000/TCP 3m22s
service/kube-test-nginx NodePort 10.109.8.40 <none> 80:30081/TCP 3m22s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7d20h
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/kube-test-app 1/1 1 1 3m22s
deployment.apps/kube-test-nginx 1/1 1 1 3m22s
NAME DESIRED CURRENT READY AGE
replicaset.apps/kube-test-app-bf6f459f 1 1 1 3m22s
replicaset.apps/kube-test-nginx-6ffff769b5 1 1 1 3m22s
今回は、nginxのサービスをNodePortを利用して30081ポートを指定しているので、ブラウザで以下のURLにアクセスすると「Hello World」と表示されます。
http://[kubernetesクラスタのIP]:30081
kubernetesクラスタのIPがわからない場合は、以下のコマンドで確認できます。
$ kubectl cluster-info
Kubernetes master is running at https://192.168.1.12:6443
KubeDNS is running at https://192.168.1.12:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
まとめ
docker-composeはプログラミング開発時のローカル環境構築には便利ですが、本番運用ではkubernetesやAWSのECSのようなオーケストレーションサービスが必要になってきます。
今回は、docker-composeで行っていたことを取り敢えずkubernetesで実現してみることを目標にしてみましたので、実際に運用する場合とは異なるかもしれませんが、無事動作させることができました。
また、kubernetes側をNodePortを利用して公開しましたが、次回はIngressを利用して構築してみたいと思います。