ゼロからDjango環境構築(Windows10 WSL、Docker)
Windows 10でDockerコンテナ内にDjango環境を構築します。
経緯としては、WSLのAnaconda環境でDjangoをインストールしてマイグレーションファイルを作ろうとしたところ、以下のようなエラーが出たためです。
$ python manage.py makemigrations ImportError: Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?
詳しくは分かりませんが、AnacondaとDjangoは相性が悪いみたいです...
なので、vnen(Docker使用)環境で作り直そうと思います。
また、Dockerコンテナに構築しておくことで、ホスト環境を汚すことがなくなり、違う環境(Mac OSとか)にも全く同じ環境を展開することが出来るようになります。
さらに今回インストールするVS Codeエディタのリモート拡張機能を用いれば、開発対象のリソースがコンテナ内にあったとしてもローカルで開発するかのように作業が行えるようになります。
1.Docker Desktop for Windowsのダウンロードとインストール
https://store.docker.com/editions/community/docker-ce-desktop-windows
登録していない場合は、Sign Up → Get Docker
2.Ubuntu 18.0.4のインストール
インストールする前にWSL2をデフォルトにするよう設定を変えます。
WS2の要件はx64 システムの場合、バージョン 1903 以降、ビルド 18362 以上です。
WSL2でのUbuntu環境を作るために、以下のコマンドを実行します。
wsl --set-default-version 2
これでWSL2がデフォルトに設定されたので、Microsoft Storeから今回hUbuntu18.0.4 LTSをインストールします。
その後、再度以下のコードを実行してWSLのバージョンを確認します。
PS C:\Users\alice> wsl --list --verbose NAME STATE VERSION * Ubuntu-16.04 Stopped 1 Ubuntu-18.04 Running 2 docker-desktop-data Running 2 docker-desktop Running 2
ちなみに、WSLとWSL2ではファイルシステムが違うため、データへのアクセス方法が異なります。
WSL | ボリュームファイルシステム(VolFs/NTFS上) |
C:\Users\{User名}\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu16.04onWindows_79rhkp1fndgsc\LocalState\rootfs\ |
WSL2 | Ext4ファイルシステム(VHDX内) |
C:\Users\{User名}\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu18.04onWindows_79rhkp1fndgsc\LocalState\ext4.vhdx | |
\\wsl$\Ubuntu-18.04\ |
3.Docker Desktopの設定
1.でインストールしたDocker Desktopを開き、Settings > Resources > WSL INTEGRATION > Ubuntu-18.04を有効化し「Apply & Restart」で適用します。
Ubuntu 18.0.4を開き、docker --versionでWSL2でDockerが認識されていることを確認します。
$ docker --version Docker version 19.03.13, build 4484c46d9d
テストとしてhello-worldイメージを実行し、コンテナ一覧を出力してみます。
$ docker image ls --all REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest bf756fb1ae65 9 months ago 13.3kB $ docker container run hello-world Hello from Docker! $ docker container ls --all CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3d13e334b944 hello-world "/hello" About a minute ago Exited (0) About a minute ago trusting_mendel
hello-worldコンテナが起動されていることが確認できましたので、コンテナを削除しておきます。
コンテナを削除するときは、docker container rmの後にコンテナIDを指定します。前頭検索で指定可能です。
$ docker container rm 3d
また、dockerと打つことでDockerで使用できるコマンド一覧が表示されます。
コンテナの仕組みについては以下の記事で詳しく書かれています。
qiita.com
4.Dockerファイルの場所を変更
デフォルトではDocker HubからpullしたイメージファイルはCドライブにダウンロードされていき圧迫されていくため、下記を参考にDockerイメージファイルの場所をDドライブに変更します。
qiita.com
5.Dockerイメージの作成
コンテナ作成の元となるイメージファイルを作成します。
まず、Docker Hubからイメージをダウンロード(pull)します。
コマンド | docker pull {イメージ名}:{タグ名} |
イメージ名とタグ名は下記Docker Hubページから探します。
https://hub.docker.com/
今回は、ubuntu:l20.10と指定し、ubuntuのバージョン20.10のイメージをダウンロードします。
$ docker pull ubuntu:20.10 $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu 20.10 da5958a2de8e 36 hours ago 79.5MB
Dcokerfileは以下のGithubページのコードを流用させて頂きます。
https://github.com/akiyoko/django-book-mysite-sample/blob/master/Dockerfile
mysiteというディレクトリを作成し、その直下に下記コードをDockerfileという名前で保存します。
FROM ubuntu:20.10 ENV PYTHONUNBUFFERED 1 ENV PYTHONIOENCODING utf-8 ENV HOME /root ENV DEPLOY_DIR ${HOME}/mysite RUN apt update \ && apt install -y sudo \ && apt -y upgrade # Set locale # https://stackoverflow.com/a/28406007 RUN apt install -y locales RUN sed -i -e "s/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/" /etc/locale.gen \ && locale-gen ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 # Install Python 3.8 RUN apt install -y wget \ build-essential \ zlib1g-dev \ # https://stackoverflow.com/a/43923402 libssl-dev \ # https://stackoverflow.com/a/29862854 libsqlite3-dev WORKDIR ${HOME} RUN wget https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tgz \ && tar zxf Python-3.8.0.tgz \ && cd Python-3.8.0 \ && ./configure --enable-optimizations \ && make altinstall # Set alias RUN update-alternatives --install /usr/local/bin/python3 python /usr/local/bin/python3.8 1 RUN update-alternatives --install /usr/local/bin/pip3 pip3 /usr/local/bin/pip3.8 1 RUN pip3 install -U pip # Install other requisites RUN apt install -y vim RUN mkdir -p ${DEPLOY_DIR} WORKDIR ${DEPLOY_DIR} # Install packages for project ADD requirements.txt . RUN pip3 install -r requirements.txt CMD ["/bin/bash"]
requirements.txt には、Djangoだけインストールするように書いてます。
Django==3.1.2
その後、dockerイメージをビルドします。
$ docker image build -t mysite:1.0 .
tオプションでイメージ名:タグ名を指定します。
. はDockerfileの保存場所(カレントディレクトリ)を指定しています。
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE mysite 1.0 39782a5aeaca 42 seconds ago 991MB ubuntu 20.10 da5958a2de8e 4 days ago 79.5MB
6. コンテナ作成
次のコマンドでDockerイメージからコンテナを作成します。
$ docker container run -it -p 8000:8000 -v /home/py/mysite:/root/mysite --name mysite mysite:1.0
-t | コンテナの中に疑似ターミナルを割り当てる |
-i | 標準入力(STDIN)を取得 |
-v | ボリュームを割り当てる(マウント)ホスト:コンテナ |
--name | コンテナ名 |
mysite:1.0 | イメージ名:タグ名 |
今回、Dockerfileの中でCMD ["/bin/bash"]と設定しているため、docker runでの記述は不要です。
itと/bin/bashはセットで使用します。
これでホストディレクリがコンテナのディレクトリにマウントされた状態でコンテナが起動します。
root@cd0c0a5f847d:~/mysite# ls Dockerfile requirements.txt test.php venv root@cd0c0a5f847d:~/mysite# pwd /root/mysite
通常は、マウントしたホストディレクトリをプロジェクトフォルダとして作業していきます。
コンテナのターミナルから抜けたい場合はexitを打ちます。
Dockerの操作
存在しているDocker一覧 | $ docker container ls -a |
起動しているDocker一覧 | $ docker container ls |
起動しているDockerの停止 | $ docker container stop {コンテナ名} |
起動しているDockerの削除 | $ docker container rm {コンテナ名} |
Python3のインストール
コンテナ内にPythonをインストールすればいいので、必ずホストOSにPythonをインストールする必要もないかもしれませんが、
Pythonのインストール方法もメモします。
執筆時点でPython 3.8がリリースされていたので、3.8をインストールします。
$ sudo apt update $ sudo apt install -y python3.8 $ python3 -V Python 3.6.9
3.8をインストールしたのに、3.6.9となってます。
Ubuntu18.0.4のインストールした初期からPython3.6.9もインストールされてたみたいです。
$ ls /usr/bin/ | grep python python3 python3-jsondiff python3-jsonpatch python3-jsonpointer python3-jsonschema python3.6 python3.6m python3.8 python3m
しっかり3.8もインストールされているみたいで、切り替える必要があります。
$ sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.6 1 $ sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.8 2 $ sudo update-alternatives --config python There are 2 choices for the alternative python (providing /usr/bin/python). Selection Path Priority Status ------------------------------------------------------------ * 0 /usr/bin/python3.8 2 auto mode 1 /usr/bin/python3.6 1 manual mode 2 /usr/bin/python3.8 2 manual mode Press <enter> to keep the current choice[*], or type selection number: 2 $ python -V Python 3.8.0
update-alternatives --install [symbolic link path] python [real path] number
という風で、pythonのバージョンを登録することで切り替えられるようになります。
(pythonと打つと/usr/bin/pythonが呼び出され、そこは/etc/alternatives/pythonを参照します。さらにその参照先を今回は/usr/bin/python3.8にした感じ)
ちなみに、python3と打つと3.6.9が参照されています。
$ python3 -V Python 3.6.9 $ which python3 /usr/bin/python3
python3はpythonとは元々2系と3系を分けるために存在しているようですが、2系は自分は使わないので別にこれで良いと思います。
パッケージ管理ツールpipのインストールとアップグレードも行います。
$ apt install python3-pip $ python -m pip install --upgrade pip $ pip --version WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip. Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue. To avoid this problem you can invoke Python with '-m pip' instead of running pip directly. pip 20.2.3 from /home/py/.local/lib/python3.8/site-packages/pip (python 3.8)
pipはそのままpipと打つと上記のようにWARNINGが出ます。
この書き方は古いようで、python -m pipという記法が正しいとのことです。
$ python -m pip -V pip 20.2.3 from /home/py/.local/lib/python3.8/site-packages/pip (python 3.8) $ python3 -m pip -V pip 9.0.1 from /usr/lib/python3/dist-packages (python 3.6)
これもpython3と打つと、3.6環境のpip(インストールしただけでアップグレードしていないpip)を参照します。
.bash_aliasesファイルにalias pip='python -m pip'と記述しておけば、pipだけで済むので楽です。
venv仮想環境構築
コンテナ自体が仮想環境のように環境構築できるため、別途venv仮想環境も要らないとは思いますが、
一応venvの使い方もメモ。
venvはPythonの仮想環境を簡単に構築する機能で、主にpip(パッケージ管理ツール)でインストールするパッケージをプロジェクトごとに分けたい時に利用します。
Python3.3~標準でインストールされており、基本的に1プロジェクト1venv仮想環境を用意します。
また、Python3.5~は仮想環境を作成する際にはvirtualenvやpyenvではなくvenvが推奨されています。
今回はDjangoプロジェクトとして、mysiteディレクトリを作成し、そこにvenv仮想環境を構築します。
$ mkdir mysite $ cd mysite $python3 -m venv venv
これでvenvという名前の仮想環境が作られます。
仮想環境のアクティベート
$ source venv/bin/activate (venv) $ python -V Python 3.8.0
venv仮想環境内のPythonバージョンはローカルのPythonバージョンと同じになります。
(venv) $ pip --version pip 9.0.1 from /home/{User名}/mysite/venv/lib/python3.8/site-packages (python 3.8)
pipのバージョンもvenv仮想環境を参照しているため9.0.1のままですので、アップグレードします。
(venv) $ pip install --upgrade pip (venv) $ pip --version pip 20.2.3 from /home/{User名}/mysite/venv/lib/python3.8/site-packages/pip (python 3.8)