Solist Work Blog

Software engineer

DjangoをlocalのKubernetesで動かす

この記事ではDjangoをlocalのKubernetesで動かす方法について書いていきます。

Djangoであれば以下のようにpipenvできちんと環境分離ができるのでdockerdocker-composeをlocalで動かす意味やうまみはほとんどありませんが、 DjangoGKEなどのKubernetesで動くかとうかをまずlocalでテストしたいという需要はあります。

pipenv install
pipenv run python manage.py migrate
pipenv run python manage.py runserver

localでKubernetes clustersを動かす場合について次のような候補があるでしょう。

  1. VirtualBoxなどのVMminikube
  2. KVMminikube
  3. kind (Kubernetes IN Docker)

1はVM上にminikubeをインストールするので重いです。 2もVMですが、VirtualBoxよりKVMのほうが軽いので少しましになりますがまだ重いのは否めません。 minikubeDjangoを立ち上げただけでロードアベレージが2を超えるので、Thinkpad X1 Carbon(Core i5)が熱くなります。 この状況ではラップトップで開発しようという気力はなくなります。 3のkind (Kubernetes IN Docker)を使って構築してみたところkindKubernetesDjangoを起動してロードアベレージ0.5くらいで収まったので、 実用的なlocalのKubernetes clustersだと思います。

kind (Kubernetes IN Docker)

まずkindをインストールしましょう。

GO111MODULE="on" go get -u -v sigs.k8s.io/kind@v0.5.1

以下でkindのコマンドがzshで補完できるようになりますが、この記事を書いている時点では壊れています。

sudo sh -c "kind completion zsh > /usr/share/zsh/site-functions/_kind"

インストールが終わったらいよいよlocal Kubernetes clusterを作ります。

kind create cluster
export KUBECONFIG="$(kind get kubeconfig-path --name="kind")"
kubectl cluster-info

kindでlocal kubernetes cluster

あとはkubectlコマンドでGKEでやるのとほぼ同じようにできるのですが、 GKE(本番環境)とkind(テスト環境)とpipenv(開発環境)の3つの環境が存在するので環境変数で3つの環境に対応できるようにしなければいけません。 環境ごとに違う設定が必要なものについては環境変数から読むように変更します。

setting.py

SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')

DATABASES = {
    'default': {
        'ENGINE': os.environ.get('DJANGO_ENGINE'),
        'HOST': os.environ.get('DJANGO_HOST'),
        'PORT': os.environ.get('DJANGO_PORT'),
        'NAME': os.environ.get('DJANGO_DBNAME'),
        'USER': os.environ.get('DJANGO_DBUSER'),
        'PASSWORD': os.environ.get('DJANGO_DBPASSWORD'),
    }
}

EMAIL_HOST_USER = os.environ.get('DJANGO_EMAIL_USER')
EMAIL_HOST_PASSWORD = os.environ.get('DJANGO_EMAIL_PASSWORD')

pipenvは.envファイルがあると環境変数として考慮してくれるので以下のようなDockerfileを用意してENVを投げ入れるようにしておくと GKE(本番環境)とkind(テスト環境)とpipenv(開発環境)の3つの環境に対応できます。

Dockerfile

FROM python:3.7

ARG ENV

RUN mkdir /code/
WORKDIR /code/
COPY ./ /code/

RUN pip install --upgrade pip && \
	pip install pipenv && \
	pipenv --python /usr/local/bin/python && \
	pipenv install

COPY $ENV /code/.env
CMD pipenv run python manage.py collectstatic
CMD pipenv run gunicorn yourproject.wsgi:application --bind 0.0.0.0:8000

静的コンテンツはdjango-storagesを利用するとpipenv run python manage.py collectstaticするだけでGoogle cloud storageに反映されます。 テスト環境と本番環境でバケット名を分けたほうがよいので.envkindと.envgkeで設定します。 毎回面倒になるのでkindKubernetes clusterを作るコマンドをaliasでkindstartにまとめます。 ついでに終了するkindstopも.bashrcか.zshrcに追加しておきます。

alias kindstart='kind create cluster; export KUBECONFIG="$(kind get kubeconfig-path --name="kind")"; kubectl cluster-info'
alias kindstop='unset KUBECONFIG; kind delete cluster'

local kubernetes clusterを作ります。

kindstart

ビルドする。このとき.envkindというファイルから環境変数をkind用のDockerfileに投げ入れます。

docker build -t myapp/django:v1 --build-arg ENV=".envkind" .

.envkind(.env .envgkeも同様に設定する)

export DJANGO_SECRET_KEY='djangoのシークレットキー'
export DJANGO_ENGINE='django.db.backends.postgresql'
export DJANGO_DBPASSWORD='テスト環境のパスワード'
export DJANGO_HOST='テスト環境のDBサーバー'
export DJANGO_PORT='5432'
export DJANGO_DBNAME='awesomedb'
export DJANGO_DBUSER='awesomeapp'
export DJANGO_EMAIL_USER='yourtestgmail@gmail.com'
export DJANGO_EMAIL_PASSWORD='gmailのimapパスワード'
export GS_BUCKET_NAME='Google cloud storageテスト環境のバケット名'
export DEBUG=False

.env .envkind .envgkeなどの環境変数は機密情報を扱うのでgit-cryptで暗号化しておきます。 まずGnuPGで鍵を生成します。GnuPGで鍵を作る方法はこちらの記事を参考にしてください。 Djangoのプロジェクトディレクトリで以下のコマンドを実行します。

git-crypt init

.gitattributesファイルを作り暗号化したいファイルを定義する。

.env filter=git-crypt diff=git-crypt
.envkind filter=git-crypt diff=git-crypt
.envgke filter=git-crypt diff=git-crypt

.gitattributesをgitにコミットする。

git add .gitattributes
git commit -m 'Add encrypted file config'

復号化できるユーザーのGPGキーを指定する。復号化できるユーザーは何もしなくても復号化されたファイルが見えるようになります。

git-crypt add-gpg-user YOUR_GNUPG_ID

これで.env .envkind .envgkeは暗号化されるので気兼ねなくGitHubにコミットできるようになります。

開発環境の環境変数は.envなのでそのままpipenvが読み込んでくれます。 GKEの環境変数は.envgkeにしてGKEのビルド時に同じようにDockerfileのENVに投げ込むようなMakefileを書いておきます。 テスト環境のデータベースはKubernetesに置いてもうまみがないので適当なサーバーに投げておきます。 開発環境のデータベースは色々できるようにlocalのPostgreSQLを使うように.envに書いておきます。

django.yaml

kind: Deployment
apiVersion: apps/v1
metadata:
  name: django
spec:
  replicas: 1
  selector:
    matchLabels:
      app: django
  template:
    metadata:
      labels:
        app: django
    spec:
      containers:
        - name: django
          image: "myapp/django:v1"
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8000
              name: django

テスト用なのでレプリカは1にしています。

kind load docker-image myapp/django:v1

ビルドしたイメージをkindに取り込みます。

kubectl apply -f django.yaml
kubectl port-forward deployment/django 8000:8000

ブラウザでlocalhost:8000で動いていればlocalのKubernetesDjangoが動いていることになります。

kindでmigrationする場合は以下のようにすればできるでしょう。

kubectl exec deployment/django -- bash -c 'pipenv run python manage.py migrate'

ついでにCircleCIも仕込んでおきましょう。

.circleci/config.yml

version: 2

jobs:
  test:
    docker:
      - image: circleci/python:3.7
      - image: circleci/postgres:11-alpine
        environment:
          POSTGRES_DB: awesomedb
          POSTGRES_USER: awesome
          POSTGRES_PASSWORD: "ok"
    working_directory: ~/repo

    steps:
      - checkout
      - run: sudo chown -R circleci:circleci /usr/local/bin
      - run: sudo chown -R circleci:circleci /usr/local/lib/python3.7/site-packages
      - run:
          name: install dependencies
          command: |
            pip install --upgrade pip
            pip install pipenv
            pipenv --python /usr/local/bin/python
            pipenv install

      - run:
          name: run tests
          command: |
            rm .env
            pipenv run python manage.py test
          environment:
            DJANGO_SECRET_KEY: 'ok'
            DJANGO_ENGINE: 'django.db.backends.postgresql'
            DJANGO_DBPASSWORD: 'ok'
            DJANGO_HOST: 'localhost'
            DJANGO_PORT: ''
            DJANGO_DBNAME: 'awesomedb'
            DJANGO_DBUSER: 'awesome'
            DEBUG: True

workflows:
  version: 2
  test:
    jobs:
      - test

タグ一覧

お仕事のご相談などはこちらからどうぞ

お仕事の依頼はこちらからどうぞ