2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Django製CMSを動かすためのk8s環境をdocker for macで構築して実行する

Last updated at Posted at 2019-11-17

前回までのあらすじ

DjangoにCodeRed CMSを投入し、同時にmarkdownも使えるようにしたコンテナ初心者。このアプリケーションを実際に使えるようにするために、コンテナの総本山、k8sでの環境の作成を開始する。

Qiita Django + Wagtail + Puput + CodeRedCMS + markdownのGit分散型ノベルアプリケーションをつくる: https://qiita.com/GCkurabe/items/a615fff1ce0be64e58ba

今回の内容

ついにk8sに着手しました。ここまで一つのVMのなかでプロセスをぶったぎりながらコンテナをつくってきましたが、これをいよいよVM間で冗長構成したりスケーリングできるようにしていきます。もともとGKEかEKSでこのCMSアプリを動かせるようにしたいと考えながらはじめてきて、ついにという感じです。

そして今回から完全にdocker for macへと移行しました。本当ならvagrantベースでのminikubeを使いたかったのですが、あまりにも動作が不安定だったためです。実際にdocker for macで非常に快適に動かせているので、このまま使っていこうとおもっています。

そして、そもそもdjangoでのk8sアプリを三階層CL-SV構成で動かすというものはドキュメントが一切ありませんでした。なのでrailsをk8sで動かすという記事や、書籍などなどを大量に参考にさせていただき、試行錯誤を繰り返しました。結局k8sで動作させるまでにえらい時間がかかってしまいました。

だいぶしんどかったので、他の人たちが楽に使えるように以下のリポジトリで公開しています。冗談みたいなSF小説を載せるためのCMSと位置付けていたので、frying_circusと名付けました。pythonの元ネタ、空飛ぶモンティパイソン(原題:Monty Python's Flying Circus)からきています。

GitHub: https://github.com/kurawo/frying_circus

Docker-composeでも開発はでき、k8sで検証を行うこともできるという構成になっています。本番環境で使えるようなセキュリティの設定は今はまだしておらず、そのためにimageもローカルからしか取得しないように作っているので、ローカルの閉鎖環境でデプロイをお願いします。

システムアーキテクチャはdocker-composeだと以下のようになります。

k8sdjango.001.jpeg

そして今回作成したk8sのシステムアーキテクチャは以下のようになります。GunicornとUpstreamの結合の関係で、NginxとDjangoコンテナをひとつのpodでまとめています。そしてIngressをnginxの前に立てることでスケーリングを行いやすいように準備をしています。三階層というよりは四階層という状態です。

k8sdjango.002.jpeg

なぜ私がk8sを選んだか

今回k8sにしたのは完全に個人で、かつコードベースでアプリ・インフラの開発と運用を少ないコードと手数で即座に行えるようにするためです。

EC2とかのVMでもdocker-compose環境を用意すれば現状と同じ環境をリリースできるのですが、スケーリングの問題が解決できなくなることと、個人で人を雇える金はない、という背景から人を増やして対応というのが到底できそうにありません。

つまりdocker-composeでデプロイしてそのあと人月を消費するくらいなら、いっそ事前にk8sで建ててすぐいじれるようにしておこう、というわけです。

私だってk8sの要件でなければさばけないトラフィックなんてほぼないとは思ってます。いんふるえんざ(誤用)でもありませんし......

しかしそれはそれとして、インフラ周りの対応を疎かにする気にもなれません。どうせDockerでアプリを作っていくならば、いっそわかるところまで全部コンテナベースで構築しておきたい。さらに可能ならそれを誰かに改造したりしてもらいながら使ってもらえたらいい。そういう非常に軽い気持ちで、k8sでも使えるようにしました。気持ちとは裏腹に大変重い対応になりました。

バズワードなわりにk8sの情報は少なく、構築もあまりにしんどいので、社内でもすべてコンテナベースで管理しようみたいな過激な話がない限りはk8sでの導入は今のところはあまり考えてはいません。まずk8s使いどころかコンテナ使いが弊社にはいないからです。しかもLinuxベースですらない弊社ではまずコマンドを教え込むところからスタートしなければなりません。夢のまた夢レベルで大変です。なのでまずは小さな社内ツールをdocker-composeで動かしているのでそれを教材にしていろんな人にLinuxとコンテナのおいしいところを覚えてもらっているところです。Linuxを触れて定時で帰りたい人はぜひ弊社に。ゆるい環境で一緒にLinux布教しましょう。

Docker for Macの準備

本題に入ります。今回からはdocker for macを使用することとしました。minikubeがうまく動かせなかったりしたためです。

インストールの手順は以下の記事を参考にさせていただきました。ダッシュボードもいれています。これはk8sに慣れないうちはほぼすべての情報がコマンド抜きで確認できるため大変重宝します。

DockerをMacにインストールしてKubernetes Dashboardにアクセスしたメモ https://qiita.com/pnpnd1111/items/2140f7941cfe3995fc17

特によく使うURLとコマンドを書いておきます。

ダッシュボード起動コマンド

$ kubectl proxy

ダッシュボードのURL

http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/

権限情報を確認するコマンド

$ kubectl -n kube-system get secret

トークンを確認するコマンド

$ kubectl -n kube-system describe secret deployment-controller-token-xxxx

これでログインできただけでもとても感動しました。execも使えてlogも見えます。よくできています。

Kompose convertを使ってみようとしたがボリュームマウントで阻まれる

ここで私は以前までカスタマイズを繰り返してきたdocker-compose.ymlを使って不精をしようとしました。具体的にはKomposeと呼ばれるものを使おうとしたんです。Kompse convertでdocker-compose.ymlを変換します。しかしここでトラブル発生。なんとvolume mountがサポートされていません。結構重大な設定はmountするようにしてきたのでこれは大変です。

# kompose convert
WARN Volume mount on the host "/vagrant/Distributed-Novel-Application-by-Git/django" isn't supported - ignoring path on the host
WARN Volume mount on the host "/vagrant/Distributed-Novel-Application-by-Git/puput" isn't supported - ignoring path on the host
WARN Volume mount on the host "/vagrant/Distributed-Novel-Application-by-Git/nginx" isn't supported - ignoring path on the host
WARN Volume mount on the host "/vagrant/Distributed-Novel-Application-by-Git/django/cmssite/static" isn't supported

警告なのでとりあえずkompose upしましたが起動しません。ファイル群を自力でつけなければ始められないことがわかりました。

ということで、フルスクラッチでk8sのymlファイルを書くことになりました。

k8sのymlファイル作成

記事を参考に、railsをdjangoに読み替えながら作成しました。

コピペだけでRailsをKubernetes上で最速で動かすためのガイド。GCP、AWS依存なしでDockerイメージ作成からの一部始終を紹介。 https://qiita.com/ttiger55/items/215cab36da848fba156b

悲しいことにrailsではなかったため、またdocker for desktopのためコピペまんまというわけにもいきませんでした。主にdjangoコンテナの起動時にgunicornコマンドを書き違えていて起動しないとか、nginxへのファイル引き渡しを調べないといけないとか、ingressを使えるようにする方法がdocker for desktopだと変わってしまうとか本当にいろんなことがありました。そのためひたすら地雷を踏みまくって最終的にはじめのリポジトリができています。簡単な解説はデプロイ方法と交えながら説明していきます。

デプロイ:Docker-composeでのイメージ作成と確認

まず手始めにpycmsというフォルダ名でgit cloneします。これは後々のdockerイメージ名を一致させるためです。

$ git clone https://github.com/kurawo/frying_circus.git pycms

その後、cloneしたフォルダに入り、事前にローカルでdjango用のベースイメージを作成します。

$ docker build -t django2.1 -f ./django/Dockerfile.base ./django

完了したらdocker-composeを使用してイメージのビルドと起動確認を行います。

$ docker-compose up --build -d

無事起動できたら、以下のコマンドでdjangoコンテナの中に入ります。

[vm]$ docker-compose exec django /bin/bash
[ctr]$

その後以下のコマンドを実行して、コンテナをwebサイトとして使用できるようにします。

[ctr]$ cd cmssite
[ctr]$ python manage.py migrate
[ctr]$ python manage.py collectstatic
[ctr]$ python manage.py createsuperuser

完了したら、以下のURLから動作を確認してみてください。

http://localhost

また、admin画面は以下のURLで移動します。

http://localhost/admin

ここまで触ってみて問題ないことが確認できれば、以下のコマンドでdocker-composeを終了します。

$ docker-compose down

デプロイ:k8sのymlファイルapply

まずsampleというnamespaceを指定します。以後はsampleというくくりで確認やコマンドの入力などが行えるようになります。逆に言えば確認の時はsampleという指定がほぼ必須となります。

$ kubectl apply -f k8s/namespace/

sample.yml

apiVersion: v1
kind: Namespace
metadata:
  name: sample

postgres用の永続化ボリュームも用意します。現在は3GBと非常に小さめです。

$ kubectl apply -f k8s/volumes/postgres.yml

postgres.yml

kind: PersistentVolume
apiVersion: v1
metadata:
  namespace: sample
  name: postgres-pv
  labels:
    type: local
spec:
  capacity:
    storage: 3Gi
  accessModes:
  - ReadWriteOnce
  storageClassName: standard
  hostPath:
    path: "/tmp/postgres"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  namespace: sample
  name: postgres-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi
  storageClassName: standard

次に、postgresやdjangoで使うconfigmapを定義します。これは以前から使っているdocker-compose.ymlと設定は同じです。

$ kubectl apply -f k8s/config/django.yml

k8s/config/django.yml

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: sample
  name: django-config
data:
  DJANGO_ENV: 'development'
  PSQL_HOST: 'postgres'
  PSQL_USER: 'root'
  PSQL_ROOT_PASSWORD: 'hogemojahogemoja'

今度はJobを登録します。Jobはpython manage.py migrateをやってもらうために用意しています。

$ kubectl apply -f k8s/settings/django-jobs.yml

k8s/settings/django-jobs.yml

apiVersion: batch/v1
kind: Job
metadata:
  namespace: sample
  name: setup
spec:
  template:
    metadata:
      name: setup
    spec:
      containers:
      - name: setup
        image: pycms_django
        imagePullPolicy: Never
        args:
          - sh
          - -c
          - "cd cmssite && python manage.py migrate"
        envFrom:
        - configMapRef:
            name: django-config
      restartPolicy: Never

nginx用のconfigも起動します。この中にはnginx.confとmime.typesを|と改行を使用して取り込んであり、これが最終的にpodにマウントされるようになっています。

$ kubectl apply -f k8s/config/nginx.yml

k8s/config/nginx.yml

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: sample
  name: nginx-config
data:
  nginx.conf: |
  #以下省略

さらに、以下のディレクトリに入ってnginx用のDockerfileを実行して新たなnginxイメージを作成します。これはnginxに使用する静的ファイルを引き渡すためです。k8sは基本的にvolumeをマウントできないため、こうしてありとあらゆる方法を使用してk8sで起動できるようにする必要があるのです。

$ cd django/cmssite
$ docker build -t nginxstaticplus -f Dockerfilenginx .

ここで、ついにnginxとdjangoが同一podとなっているものを立ち上げます。Djangoではgunicornを使用して3031ポートで起動し、nginxではnginx.confをもとに3031ポートをupstreamで立ち上げて8080ポートに引き渡します。

またdjangoもnginx同様にデプロイ後のローカルのイメージをそのまま活用し、imageの名前はpycms_djangoとしています。もしもうまく取得できなかった時はdjangoのimageの名前をpycms_djangoにしてから再度実行をお願いします。

クラウドで使用する場合にはDockerHubにあげるなりなんなりする必要があります。

$ kubectl apply -f k8s/settings/nginxdjango.yml

k8s/settings/nginxdjango.yml

apiVersion: v1
kind: Service
metadata:
  namespace: sample
  name: nginxdjango
spec:
  selector:
    app: nginxdjango
  type: NodePort
  ports:
  - port: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: sample
  name: nginxdjango
spec:
  selector:
    matchLabels:
      app: nginxdjango
  template:
    metadata:
      labels:
        app: nginxdjango
    spec:
      containers:
      # django container
      - name: django
        image: pycms_django
        imagePullPolicy: Never
        args:
          - sh
          - -c
          - "cd cmssite && gunicorn cmssite.wsgi -b 0.0.0.0:3031"
        envFrom:
        - configMapRef:
            name: django-config
        ports:
        - containerPort: 3031
      # nginx container
      - name: nginx
        image: nginxstaticplus
        imagePullPolicy: Never
        volumeMounts:
        - mountPath: /etc/nginx # /etc/nginxにvolumesのnginx-confをmountする
          readOnly: true
          name: nginx-config
        - mountPath: /var/log/nginx
          name: log
      volumes:
      - name: nginx-config # volumeMountsで/etc/nginxにmountするやつ
        configMap:
          name: nginx-config # ConfigMapのnginx-configを/etc/nginx以下に配置する
          items:
            - key: nginx.conf # nginx-confのkey
              path: nginx.conf # nginx.confというファイル名
            - key: mime.types
              path: mime.types
      - name: log
        emptyDir: {}

最後にingressを用意します。ingressは以下のコマンドでインストールしますが、helmが必要なため事前に用意した後でこのコマンドを実行してください。

$ helm install stable/nginx-ingress

そして以下のコマンドでingressを起動します。現在は全ての接続を8080ポートにつなげるという仕組みになっており、これでnginxとdjangoのpodと接続することができます。必要であればここにルールを継ぎ足すことでスケーリングが可能となります。

$ kubectl apply -f k8s/settings/ingress.yml

k8s/settings/ingress.yml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  namespace: sample
  name: ingress
spec:
  rules:
  - host:
    http:
      paths:
      - path: /
        backend:
          serviceName: nginxdjango
          servicePort: 8080

最後にローカルホストへアクセスすれば、docker-composeと同様の画面を確認することができます。

http://localhost

おわりに

なんとかk8sでアプリケーションを動かすことができるようになりました。本当に大変でした。しかしこれをプレーンなVMで作ろうと思ったらスケーリングの段になった瞬間一切手足が出なくなっていたと思います。これからはスケーリングや冗長構成などをこのk8sのymlファイルを編集していくことでつくっていくことができます。

次回はアプリケーションの改良を行いつつ、スケーリングや冗長構成を含め、最後にクラウド上にデプロイしていきます。

2
4
0

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
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?