😊

Dockerをさわってみる②(Dockerfile)

2021/05/06に公開

はじめに

前回はこちらで、Dockerを動かすための環境構築の実施とWordPressのDockerイメージを実行しました。

今回は、自分でDockerイメージ(Django)を作成し、それを実行して動作確認をするところまでのハンズオンを実施したいと思います。

ローカル開発環境

  • Windows 10 Pro
  • Python 3.9.1

ハンズオンの流れ

  1. ローカルでDjangoのサンプルアプリケーションを作成する。
  2. リモートサーバーに上記プロジェクトをアップロードする。
  3. Dockerfileを記述する。
  4. Dockerイメージをビルドする。
  5. Dockerコンテナを起動し、動作確認をする。

Dockerfileとは

Dockerイメージを作成する際に必要なライブラリやアプリケーションをパッケージ化する際に必要なファイルのこと。Dockerfileによりこのような作業が自動化され、Dockerイメージの作成ができるようになります。

DockerfileはMakefileのように、Dockerで定義されている書式にのっとってアプリケーションのインストールなどを行い、Dockerイメージの作成を行います。

Dockerfileの書式は以下を参照ください。
https://docs.docker.jp/engine/reference/builder.html

Djangoとは

Django(ジャンゴ)とは、

Pythonで実装されたWebアプリケーションフレームワーク。MVCデザインパターンに緩やかに従う。

https://ja.wikipedia.org/wiki/Django

ハンズオン

Djangoのサンプルアプリケーションを作成する

まずはローカル開発環境で動作するDjangoのアプリケーションを作成します。
以下のサイトとほとんど同一の手順を実施します。
https://www.indetail.co.jp/blog/190208/
※この後めちゃくちゃ上記記事の文章を引用します。

  • Djangoのインストール
pip install Django

Vesion3.2が入りました。

$ pip freeze
Django==3.2
  • Djangoプロジェクトの作成 (今回はMyDjangoProjectというプロジェクト名にします。)
django-admin startproject MyDjangoProject
  • Djangoアプリケーションの作成(今回はMyDjangoAppというアプリケーション名にします。)
python manage.py startapp MyDjangoApp
  • veiwの作成

Djangoのviewは、リクエストを受けてhtmlテンプレートの呼び出しと値の受け渡しを行ってくれます。
view自体はviews.pyという名前でアプリディレクトリ内に生成されているので、views.pyを編集します。
今回は以下のように、index.htmlを呼び出すように書き換えました。

view.py
from django.shortcuts import render

# Create your views here. (templatesディレクトリ内mydjango/index.htmlを呼び出し)
def index(request):
    return render(request, "mydjango/index.html")
  • テンプレートの作成

先ほどのviewに記載したテンプレートのindex.htmlを作成します。
テンプレートはアプリディレクトリ内の以下のディレクトリ下に作成します。
templates/

mydjango/index.html
<html>
<body>
  Hello, MyDjangoApp!!!!
</body>
</html>
  • ルーティングの設定

表示するviewの設定ができましたので、ルーティングの設定をします。
ルーティングの設定はurls.pyというファイルを使って設定します。こちらはアプリ作成時に自動生成されないため、手動で作成します。
今回は「http://127.0.0.1:8080/mydjango/」で表示できるようにしようかと考えていますのでアプリディレクトリにurls.pyを作成して以下のように記載しました。

urls.py
from django.conf.urls import url

from . import views 

# root URLに接続するとindexが表示されるように設定
urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'index.html', views.index, name='index'),
]

プロジェクトディレクトリのurls.pyを以下のように設定し、
http://127.0.0.1:8080/ 直下の「mydjango/」 のURLをMyDjangoAppアプリに割り振ります。
※アプリ側には自動生成されませんが、プロジェクト側にはurls.pyが自動生成されますので新規作成は不要です。

urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import include,url

urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^mydjango/', include('MyDjangoApp.urls')),
]
  • 設定ファイルにアプリケーションを追加

最後にプロジェクト側をアプリと結びつけをする必要があるので、プロジェクトディレクトリ内のsettings.pyを書き換えます。
書き換える内容は以下のように、INSTALLED_APPS内にアプリを追加します。

setting.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 以下を追加
    'MyDjangoApp',
]
  • サーバーの起動
    以下のコマンドでサーバーを起動します。
cd MyDjangoProject
python manage.py runserver 127.0.0.1:8080

ブラウザで、http://127.0.0.1:8080/mydjango/ にアクセスして、以下の画面が表示されれば準備完了です。

リモートサーバーにアップロードする

ここからは、上記で作成したDjangoアプリケーションを、リモートサーバー上のDockerコンテナ上で起動することを目指します。

ec2-userでサーバーにログインし、適当なディレクトリを作り、そこに移動します。

$ mkdir django
$ cd django
$ pwd
/home/ec2-user/django

ここに以下のような階層でファイルをアップロードします。

django
├── Dockerfile
├── requirements.txt
└── MyDjangoProject
    ├── manage.py 
    ├── MyDjangoProject
    |   ├── __init__.py
    |   ├── asgi.py
    |   ├── setting.py
    |   ├── urls.py
    |   └── wsgi.py
    └── MyDjangoProject
        ├── __init__.py
	├── admin.py
	├── apps.py
	├── models.py
	├── tests.py
	├── urls.py
	├── views.py
	└── templates
	    └── mydjango
                └── index.html

MyDjangoProjectはローカル開発環境で、構築した階層と同じです。
Dockerfileが、Dockerイメージを作成するために必要なファイルです。
requirements.txtはDockerイメージを作成する際に、パッケージ化するライブラリ群を記述したものです。
次から、Dockerfile, requirements.txtの中身を記載していきます。

Dockerfileを記述する

今回はDockerfileに以下を記述しています。

Dockerfile
# 1. ベースとなるイメージを指定
FROM python:3.9

# 2. 作業ディレクトリの作成
RUN mkdir /src

# 3. 作業ディレクトリの設定
WORKDIR /src

# 4. カレントディレクトリにあるファイルをコンテナ上の指定のディレクトリにコピーする
ADD . /src

# 5. pipでrequirements.txtに指定されているパッケージを追加する
RUN pip3 install -r requirements.txt

# 6. dbのmigration
RUN python3 ./MyDjangoProject/manage.py migrate

# 7. 起動(コンテナのポート8080番で受け付けるように起動する)
CMD python3 ./MyDjangoProject/manage.py runserver 0.0.0.0:8080
  1. FROMで、ベースとなるベースイメージを指定します。今回はpythonのバージョン3.9を指定します。(ローカル開発環境と同じ)
  2. RUNで、作成されるコンテナ内で、Linuxのコマンド(mkdir)を実行します。
  3. WORKDIRで、ワークディレクトリを移動します。(Unixのcdみたいなもの)
  4. ADDで、現在のパスに存在するファイルを、コンテナ内の/srcディレクトリにコピーします。
  5. RUNで、pipコマンドを実行して、requirements.txt内に記載されているライブラリをコンテナイメージ内にインストールします。(python2系もEC2にインストールされているので、pip3としています。)
    requirements.txtには以下を記載します。
requirements.txt
Django==3.2
uwsgi==2.0.17

Djangoはローカルでインストールしたバージョンと同じものをインストールします。
uwsgiは以下です。

uWSGIとはPythonでWebサービスを動かすためのアプリケーションサーバ(以降、APサーバーと略することがあります。)の一種です。

https://www.python.ambitious-engineer.com/archives/1959#uWSGI

  1. RUNで、データベースのmigrationを実行します。

migrate コマンドは INSTALLED_APPS の設定を参照するとともに、 mysite/settings.py ファイルのデータベース設定に従って必要なすべてのデータベースのテーブルを作成します。

https://docs.djangoproject.com/ja/3.2/intro/tutorial02/

  1. CMDでDockerコンテナ起動時の動作を記述します。ここではアプリケーションサーバーの起動を実施します。

Dockerイメージをビルドする

Dockerファイルができたら次はDockerイメージをビルドします。
以下のコマンドでビルドします。

docker build -t djangoimage .

docker build [オプション] パスでビルドすることができます。パスは、Dockerfileのパスを指定します。ここではカレントディレクトリにDockerfileが存在するので、.を指定します。-tオプションで、Dockerイメージの名前を指定します。ここではdjangoimageとしました。

(参考)
https://docs.docker.jp/engine/reference/commandline/build.html

Dockerコンテナを起動し、動作確認をする

最後に、作成したDockerイメージをもとに、Dockerコンテナを起動します。
以下のコマンドで実行します。

docker run --rm -p 8080:8080 djangoimage

docker run [オプション] イメージでDockerコンテナを起動することができます。
イメージには、Dockerイメージ名djangoimageを指定します。--rmオプションで、コンテナ終了時に、コンテナを削除します。-pオプションでコンテナ上のポート(8080)をホスト側のポート(8080)に公開します。
※ホスト側を80にしてもいいのですが、前回作った環境をそのまま使ったので、8080にしました。

(参考)
https://docs.docker.jp/engine/reference/commandline/run.html

コンテナが起動したら、http://{パブリックIPアドレス}:8080/mydjango にアクセスしてみます。

おや、接続できない。
以下に解決方法が。

https://yukun.info/django-invalid-http_host-header/

MyDjangoAppのsetting.pyのALLOWED_HOST'*'を追加

setting.py
+ ALLOWED_HOSTS = ['*']
- ALLOWED_HOSTS = []

dockerイメージを再度作り直すところから始めて、コンテナを起動。再度アクセスしてみます。

できた!
※エラー画面とIPが違いますが、サーバー再起動によりグローバルIPアドレスが変わってしまったためです。特に気にしなくてかまいません。

まとめ

今回は、Dockerfileを記述して、DjangoのDockerイメージを作成し、コンテナを起動しました。
Dockerfileを一度作成すれば、Dockerが動いている環境であればいつでも再利用可能なのが良いですね。

次回はコンテナを複数起動し、それらを管理するためのDocker Composeを使ってみたいと思います。

以上です。

Discussion