Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

pipenvとGitとDockerを使ったPython開発フロー

はじめに

最近話題のpipenvですが、実際にどのような開発フローをするのかわかりづらいところがあります。この記事ではGitとDockerの利用を前提としつつ、pipenvを使うための開発フローを解説します。

全体の流れ

  1. 開発環境のインストール
  2. プロジェクトの初期化
  3. Docker化

前提環境

  • Python3系
  • UnixライクなOS

開発環境のインストール

まずは開発環境のインストールです。pipenvを入れていきましょう。

pipenvのインストール

macOSの場合

Homebrewで簡単に導入可能です。

$ brew install pipenv

Arch Linuxの場合

こちらもリポジトリに登録されているので簡単に導入できます

$ sudo pacman -S python-pipenv

Ubuntu 20.04の場合

公式リポジトリからインストールできるようになりました!

$ sudo apt install pipenv

インストール後の設定

pipenvをインストールしたら、PIPENV_VENV_IN_PROJECT環境変数をセットしておきます。pipenvで作成される仮想環境はデフォルトで~/.local/share/virtualenvsに格納されますが、この設定を有効にするとプロジェクトルートディレクトリの.venvディレクトリに仮想環境が作成される挙動に変更されます。特にPyCharmで開発するときはこの.venvディレクトリをデフォルトで読み込んでくれるため、この設定を有効にしておくことをオススメします。

お使いのシェルの設定ファイル(~/.bashrc~/.zshrcなど)を開き、以下の行を追加してください。追加したら端末を再起動するかsourceコマンドを使って設定を再読込してください。

~/.bashrc
export PIPENV_VENV_IN_PROJECT=1

その他ツールの導入

これから利用するGitDockerを導入しておいてください。ここでは本題から外れるため、詳細なインストール手順は省きます。

Pythonプロジェクトの初期化

ここからはいよいよPythonプロジェクトを作成していきます。

プロジェクトの作成

適当なディレクトリを作り、pipenv installコマンドを使ってプロジェクトを初期化します。このとき--pythonオプションを使うことでpyenvを使って自動的にそのバージョンをインストールしてそこから仮想環境を切り出してくれます。

$ mkdir sample_project
$ cd sample_project
$ pipenv install
Creating a virtualenv for this project…

一連の作業が終わってからlsすると、PipfilePipfile.lockの2種類のファイルができあがっていることが確認できます。これで初期化は完了です。

$ ls
Pipfile  Pipfile.lock

Gitの初期化

続いてこのプロジェクトをGitで管理するためにGitの初期化を行います。gitignore.ioを利用して、まず.gitignoreファイルを作ってしまいましょう。今回はPythonとvirtualenvを指定して作ってもらいます。.gitignoreに追加の設定が必要な方はここで編集しておいてください。

.gitignoreができたら手元のGitリポジトリを初期化して、ざっくり全ファイルを追加してcommitしておきます。PipfileとPipfile.lockはともにGit管理下に置くことを想定しているファイルですので、忘れずにaddしておきましょう。

$ curl -o .gitignore https://www.gitignore.io/api/python,virtualenv
$ git init
$ git add Pipfile Pipfile.lock .gitignore
$ git commit -m "Initial Commit"

パッケージの追加

pipenv環境下ではpipenvコマンドを使ってパッケージをインストールします。こうすることでPipfileにそのパッケージが列挙され、その時点で解決されたバージョンやそのパッケージの依存関係にある別のパッケージの詳細がPipfile.lockに記載されます。今回は試しにDjangoをインストールしてみることにします。

$ pipenv install django

インストール後にそれぞれのファイルの中身を覗いてみましょう。

Pipfileにはdjango = "*"が追加されています。これは、インストール時点での最新版を使う設定です。もしバージョンを固定したい場合はインストール時にpipenv install django==2.0.0などとすると良いでしょう。django>=1.11.0,<2.0.0のように範囲指定をすることもできます。

Pipfile
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
django = "*"

[dev-packages]

[requires]
python_version = "3.7"

Pipfile.lockには依存関係にあるパッケージも列挙されています。また、パッケージのハッシュ値も記載されるようになっています。このハッシュ値はダウンロードされたパッケージそのものから生成されており、これによって異なる環境下でも同一のパッケージがインストールされることを保証することができます。

Pipfile.lock
{
    "_meta": {
        "hash": {
            "sha256": "627ef89f247ecee27e9ef0dabe116108d09c47abf171c900a8817befa64f9dd2"
        },
        "pipfile-spec": 6,
        "requires": {
            "python_version": "3.7"
        },
        "sources": [
            {
                "name": "pypi",
                "url": "https://pypi.org/simple",
                "verify_ssl": true
            }
        ]
    },
    "default": {
        "django": {
            "hashes": [
                "sha256:97886b8a13bbc33bfeba2ff133035d3eca014e2309dff2b6da0bdfc0b8656613",
                "sha256:e900b73beee8977c7b887d90c6c57d68af10066b9dac898e1eaf0f82313de334"
            ],
            "index": "pypi",
            "version": "==2.0.7"
        },
        "pytz": {
            "hashes": [
                "sha256:a061aa0a9e06881eb8b3b2b43f05b9439d6583c206d0a6c340ff72a7b6669053",
                "sha256:ffb9ef1de172603304d9d2819af6f5ece76f2e85ec10692a524dd876e72bf277"
            ],
            "version": "==2018.5"
        }
    },
    "develop": {}
}

もし追加のパッケージをインストールしたくなったら、その時点でいつでもpipenv installコマンドを使ってパッケージを追加してください。

また、開発時にしか使わないパッケージを導入することも可能です。例えばLinterにblackmypyを採用することにした場合、以下のように-dオプションを付けてインストールします。なおblackはstable版が存在していない都合上、バージョンを明示的に指定しないとバージョン解決に失敗してインストールできないようです。

$ pipenv install -d black==19.10b0 mypy

もろもろをインストールしたら、PipfilePipfile.lockをaddしてcommitしておきましょう。

$ git add Pipfile Pipfile.lock
$ git commit -m "install django, black and mypy"

Pythonスクリプトの実行

pipenvで作られるのは仮想環境であるため、pipenvでインストールしたパッケージを利用したPythonスクリプトを実行するためにはまずその仮想環境に入る必要があります。以下のコマンドで仮想環境に入れます。仮想環境に入るとプロンプトの先頭に仮想環境名が表示されるようになります。仮想環境を抜けるときはexitコマンドを利用します。

$ pipenv shell
(sample_project)$ python foo.py
(sample_project)$ exit

Docker化

ここからはDockerに載せるための設定をしていきます。

.dockerignoreの準備

まず余計なファイルを転送しないために.dockerignoreを書きましょう。特に.venvディレクトリは無視するようにします。その他不要なものも一緒に書いておくと良いでしょう。

.dockerignore
.mypy_cache/
.venv/
__pycache__/

Dockerfileの書き方

.dockerignoreが書けたらDockerfileを書きます。公式のPythonイメージから作っていきます。プログラムを多少変えただけなのにいちいち依存パッケージのインストールから始めるのは無駄なので、まずはPipfilePipfile.lockだけを転送し、先にパッケージをインストールしてから、Pythonスクリプトをコピーして作成したアプリケーションを実行するようにします。

また、Python公式イメージにはデフォルトでpipenvが含まれていないため、Dockerfile内でインストールする必要があります。pipenvがインストールできたら、依存パッケージをインストールします。このとき、開発用のパッケージは導入する必要が無いので-dオプションは付けないでおきます。

また、--systemオプションを使うことで、システムデフォルトのpipを使ってパッケージをインストールしてくれます。Dockerで使う場合はこのオプションを付けると良いでしょう。逆にそうしないといちいちpipenvで作成した仮想環境に入る手間が加わってしまいます。

今回はマルチステージビルドを利用して、pipenvでインストールしたPythonパッケージを動作用イメージにまるっとコピーして、出来上がりサイズを小さくできるようにしています1

Dockerfile
FROM python:3.8 AS builder

WORKDIR /usr/src/app

COPY Pipfile Pipfile.lock ./

RUN pip install pipenv \
 && pipenv install --system


FROM python:3.8-slim

ENV PYTHONUNBUFFERED=1

COPY --from=builder /usr/local/lib/python3.8/site-packages /usr/local/lib/python3.8/site-packages

COPY . ./

CMD ["python", "app.py"]

あとはよしなに開発を進めてください。

FAQ

パッケージの更新方法

pipenvで管理しているパッケージに更新があった場合は、pipenv updateコマンドでそれらのパッケージを依存関係ごとアップデートすることができます。

パッケージの削除方法

不要になったパッケージはpipenv uninstall PACKAGE_NAMEで削除できます。

途中から開発に参加した場合のパッケージインストール方法

途中から開発に参加し、まっさらな環境の人は環境構築とGitリポジトリのcloneを済ませた上で、Pipfileが存在しているディレクトリで以下のコマンドを入力すれば開発に必要なパッケージを全て導入することが可能です。

$ pipenv install -d

別のブランチでインストールされたパッケージをマージ後に適用する方法

共同開発でブランチを多数切っていると、他のブランチでもパッケージが追加されたものがmasterにマージされ、それを手元のブランチにrebaseやマージするなどして取り込んだときにPipfile.lockがコンフリクトする現象が発生します。なおPipfileの方はよしなにマージされることが多いです。よしなにマージされなくてもコンフリクト箇所を注意深く観察して手動解決できます。

Pipfile.lockがコンフリクトしている場合は、コンフリクトが発生している状態でいったん手元のPipfile.lockを削除し、新しく生成し直す方法を使います。コンフリクトが解決したら忘れずにaddしておきましょう。以下にコマンド例を示します。

$ rm -rf Pipfile.lock # お好みで`git rm`でも可
$ pipenv install
$ git add Pipfile.lock

GitリポジトリからPythonパッケージをインストールしたい場合

開発版など、Gitリポジトリにしかパッケージが存在していない場合があります。その場合も、pipenvを使ってパッケージをインストールすることが可能です。この場合少し表記が複雑になりますが

  • リポジトリのアドレス
  • コミットハッシュやタグ名などのリビジョン
  • パッケージ名

の3つを抑えておけばOkです。あとは下記のフォーマットに従って入力すれば大丈夫です。

$ pipenv install git+[git_repository_url]@[revision]#egg=[package_name]

例えば拙作のhackingのフォークをGitリポジトリから導入する場合、以下のようにします。今回は開発用にしか使わないので-dオプションを付けています。リビジョンはmasterブランチの最新のコミットから取得したものです。パッケージ名は自由に付けて良いのですが、わかりやすくhackingにしてあります。

$ pipenv install -d git+https://github.com/aruneko/hacking@733ffe4a711ed6c92063d8074410ac05c97608dc#egg=hacking

おわりに

ここまでpipenvとGitとDockerを使ったPython開発フローを紹介してきました。virtualenvなどを使っていた頃と比べるとかなりシンプルに開発できていると思います。また、Pipfile.lockのおかげで再現性のある環境をどこでも立ち上げることができるようになり、利便性も増しています。皆さんもぜひpipenvを使ってPython開発環境を快適にしてみましょう!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away