自己紹介
都内某W大学の文系大学生のtabataitです。@tabatait
投稿は久しぶりです。
普段は大学に通いつつ、過去1年半ほどGoogle AdWordsを始めとしたWeb広告運用をやったり、PHPエンジニアとして1年間仕事をしたりと、
勉学に励みつつ、修行をしつつ、仕事をしつつ奮闘しています。
今回書いていくこと
- 自分が作りたいアプリケーションの環境構築手順
- 1年前挫折したDjangoでのチャレンジ
- 初めてのPythonでの環境構築
作りたい環境
とりあえず作りたいプロダクトとしてはまだテスト段階で、
そもそもウケるのかどうかもわからないので、
後々サーバーの構築が楽になるような構成にしようと考えています。
具体的には、
- dockerを使ったコンテナベースの環境を作る。 サービスとしてイケるのであれば、Kubernetesなど、 スケーラビリティしやすい環境にも対応できるような構成にしておきたい。
- Infrastructure as codeに則り、 誰でもカンタンに環境を移植し、開発に参加できるようにしておきたい。
- 環境ごとバージョン管理したい。
なので、docker-composeを使って環境全体の構築をしていこうかと思います。
前提条件
- MacOS v10.13.3
- Python 3.6.5
- Node.js 8.11.1
- docker 17.12.0-ce-mac55 (23011)
- docker-compose 1.18.0
- pip 10.0.1
ちなみに今回なぜPythonを使用したかというと、普段はPHPを使っているのですが、
諸々の事情があってPHPを使いたくないからです。
(composer重い。。。phpのインストールに時間かかる。。。xcodeやmacのバージョンに強く依存する。。。)
Djangoセットアップ
まずはdjangoをインストールしてプロジェクトを作ってしまいます。
$ pip install django
$ django-admin startproject testApp
一旦ここまでで、アプリケーションが立ち上がるかどうか見てみます。
$ python manage.py runserver
OK!
言語のバージョン指定
言語のバージョン指定を行っていきます。
冒頭でも示している通り、Pythonのversionは3.6.5です。
環境ごとの違いをなくしていくためにもPythonのバージョンは指定しておきます。
サーバー側の言語の指定にはpyenvを使いました。
$ pyenv install 3.6.5
$ pyenv local 3.6.5
$ python --version
Python 3.6.5
ちなみに僕は普段PHPを書くので、anyenvを使って各言語のenvを管理しています。
https://github.com/riywo/anyenv
Webサーバーコンテナ構築
まずはnginxを起動します。ルートディレクトリにdocker-composeファイルを作成します。
vim docker-compose.yml
次にwebサーバーコンテナの環境の定義だけ書いてしまいます。
version: '2'
services:
web:
image: nginx:alpine
初期リリース時はそれほどスペックはいらないと思うので、
一旦軽量なベースイメージであるalpineを使用しています。
そして、開発環境用のコンテナの設定も書いておきます。
version: '2'
services:
web:
ports:
- "8000:80"
本番環境でサーバーの8000番ポートを開けることはないので、
develop用にcomposeファイルを用意し、開発時のみ使用するようにしました。
では、コンテナを立ち上げましょう。
$ docker-compose -f docker-compose.yml -f docker-compose.dev.yml up web
無事nginxの起動まで確認できました。
アプリケーションサーバーコンテナ構築
ここからがなかなか大変。
まずはpython3.6.5を搭載したイメージファイルを探してきます。
https://hub.docker.com/_/python/
次に、python_serverディレクトリを作り、そこにDockerfileを格納していきます。
requirements.txtもビルド時に組み込みたいので、追加します。
$ mkdir python_server
$ touch python_server/requirements.txt
$ touch python_server/Dockerfile
django==2.0.4
uwsgi
FROM python:3.6.5
MAINTAINER HayateTabata
RUN mkdir /server
WORKDIR /server
COPY requirements.txt /server/requirements.txt
RUN pip install -r requirements.txt
次にuwsgiの設定を追加。
$ touch ./python_server/uwsgi.ini
[uwsgi]
chdir = /server
module = testApp.wsgi:application
master = true
max-requests = 5000
processes = 5
socket = :5000
pythonコンテナ起動時のコマンドについてもここで追加。
$ touch python_server/entry.sh
$ chmod 777 ./python_server/entry.sh
#!/bin/bash
uwsgi --ini ./python_server/uwsgi.ini
nginx側の設定を追加。
$ mkdir web_server
$ touch web_server/development.conf
server {
listen 80;
server_name localhost;
location / {
uwsgi_pass python:5000;
include uwsgi_params;
}
}
これでコンテナ自体の準備が完了したので、docker-composeにサービスを定義。
version: '2'
services:
python:
build: python_server
volumes:
- .:/server
command: ./python_server/entry.sh
web:
image: nginx:alpine
depends_on:
- python
version: '2'
services:
python:
expose:
- "5000"
web:
ports:
- "8090:80"
volumes:
- ./web_server/development.conf:/etc/nginx/conf.d/default.conf
これで設定が完了したので、ビルドしてコンテナを立ち上げてみます。
$ docker-compose -f docker-compose.yml -f docker-compose.dev.yml build
$ docker-compose -f docker-compose.yml -f docker-compose.dev.yml up web
localhost:8090へアクセス。
nginxを経由して無事に表示までできました。
DBコンテナ構築
mysqlのバージョンは最新の8系を使わず、5.7.22を使用。
さすがにメジャーアップデートしたmysqlをいきなり使うのは恐ろしかったので、、、
version: '2'
services:
mysql:
image: mysql:5.7.22
restart: always
environment:
- MYSQL_ROOT_PASSWORD=testApp
- MYSQL_DATABASE=testApp
- MYSQL_USER=testApp
- MYSQL_PASSWORD=testApp
python:
build: python_server
volumes:
- .:/server
command: ./python_server/entry.sh
web:
image: nginx:alpine
depends_on:
- python
次に、Djangoとガッチャンコします。
requirements.txtに下記を追加
PyMySQL==0.8.0
PyMySQLを呼び出して初期化する必要があり、そこでめちゃくちゃハマりました。
manage.pyを叩いて開発サーバーを構築しているのであれば、manage.pyの頭の方で呼び出せばよいのですが、
uwsgiを使用しているため、wsgi.py内で呼び出さないといけないそう。
参考(https://qiita.com/nrryuya/items/506f16a246da74db9157)
そのため、get_wsgi_application関数よりも前で初期化する必要がある。
import pymysql
pymysql.install_as_MySQLdb()
~略~
application = get_wsgi_application()
最後に、settingにmysqlへのアクセスする設定を書いていきます。75行目あたり。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': os.path.join(BASE_DIR, 'testApp'),
'USER': 'testApp',
'PASSWORD': 'testApp',
'HOST': 'mysql',
'PORT': '3306',
}
}
docker-composeで設定した項目と一致した内容を書いていきます。
今更感はあるが、HOSTについてmysqlというdocker-compose内で定義した名前が使用されていますが、
dockerが名前解決を行ってくれるので、これで大丈夫です。
requirements.txtを更新したので、もう一回ビルド。
$ docker-compose -f docker-compose.yml -f docker-compose.dev.yml build
$ docker-compose -f docker-compose.yml -f docker-compose.dev.yml up web
localhost:8090へアクセス。
本日何度も見た画面。
無事起動した。。。!!!長かった。。。!!!
感想
- 思いの外環境構築にものすごい時間がかかり、特に自分が慣れていない言語やフレームワークに挑戦するのはかなりコストがかかるものであると痛感。楽しいけど意外と疲れた。。。
- さすがにenvで環境変数を分けるくらいのことはやりたい
- セットアップやコンテナ起動の簡略化(シェルスクリプトによるマクロ)はまた今度
- フロント側の環境構築も腰を据えてやりたい(webpackの導入)
- かなりサーバー側の設定が杜撰なので、ここはいずれどうにかしたい。(nginx、uwsgi周り)
- ようやくコーディングをガッツリやれると思うと心が躍る
ようやくコーディングに移れるので、Djangoで気づいたことや、
普段自分が触っているLaravel Frameworkとの感触の違いなどに触れつつ記事を追加していければなと思います。
参考
https://docs.djangoproject.com/ja/2.0/intro/tutorial01/
http://pythonskywalker.hatenablog.com/entry/2016/11/17/152830