【2時間でCI環境構築】CircleCIでPython Webサーバ構築してHTTP通信試験を通す手順

CircleCIの特徴は1環境であれば無料でCI環境が利用出来る点です。環境構築が完了すると、GitHubのcommit毎にCIコンテナが立ち上がり定義した自動テストがコンテナ上で実行されるようになります。本投稿では、Python3.5とFlaskで構築したWebサーバをCircleCI上で稼働させて、requestsを使ってコンテナ上のWebサーバにアクセスしてHTTP Statusコード200が返却されることを試験しています。

# 2時間で構築するCI環境の動作フロー
Python3.5 + Flaskで構築されたWebサーバを試験する

![スクリーンショット 2016-02-26 21.06.22.png](https://qiita-image-store.s3.amazonaws.com/0/65312/f9a09ef2-5e7b-0bb3-56eb-efca20e0b064.png)

CircleCI上でPythonのWebフレームワークであるFlaskを利用したWebサーバを立ち上げて、HTTPのエンドポイントにアクセスしてHTTP Statusを確認する簡単な試験を行うのが本記事です。

## jenkins職人問題へのCircleCIの考え方
jenkins職人問題 というのは私の狭い観測範囲内で言われている一般的でない造語です。どんな問題かというと、PJにCI環境としてjenkinsを投入すると、だいたいにおいてjenkins職人が発生して魔改造が進み便利になる一方で、jenkinsでしかdeploy出来ないのにjenkins環境が破損したときに職人しか直せない。という問題が往々に発生してしまうことです。jenkinsが必須インフラになってしまい本番環境並みに落ちないことを要求されるようになる段階で割と悲劇が起きることが多いと思います。jenkinsクラスタには出来れば関わりたくないと尊敬する先輩が言っていました。

CircleCIでは、CI環境に関する情報が **全てcircle.ymlに集約**されるため、この問題が発生しません。また1台のJenkinsにSDKを詰め込みすぎる問題も、試験毎に別途コンテナを生成する仕組みのため発生しません。


# CircleCI 構築手順書
##### 1. GitHubのアカウントを所持すること
##### 2. [CircleCIのSign Upページ](https://circleci.com/signup/)でユーザ登録する
##### 3. GitHubのリポジトリを選択して登録する
##### 4.CircleCI上でHelloWorldする
リポジトリのトップディレクトリに `circle.yml` を作成して次のように記述してcommitしましょう。commitした瞬間にhookされて自動でCircleCI上で試験が始まります。

```yaml:circle.yml
test:
  override:
    - pwd ~
    - ifconfig
    - echo HelloWorld
    - exit 0
```

■ 実行結果
![スクリーンショット 2016-02-26 19.23.07.png](https://qiita-image-store.s3.amazonaws.com/0/65312/e9aad499-a21c-b580-dc5e-674a9f0c5bfc.png)

##### 5. CircleCI上でPython3.5環境を構築する
CircleCIが対応しているPythonのバージョンについては、[こちらの公式ドキュメント](https://circleci.com/docs/environment#python)を参照してください。commitしたら自動で試験が走る。

```yaml:circle.yml
machine:
  python:
    version: 3.5.0

test:
  override:
    - pwd ~
    - ifconfig
    - echo HelloWorld
    - exit 0
```

##### 6. pipで環境構築する
pipとはRubyで言うGem, パッケージ管理システムです。CicleCIの標準手法では、リポジトリのトップディレクトリに `requirements.txt` にパッケージ名とバージョンを列挙します。詳細は[公式ドキュメント Pythonの項を参照](https://circleci.com/docs/language-python)すると良いです。

```yaml:circle.yml
machine:
  python:
    version: 3.5.0

dependencies:
  pre:
    - pip install -r ./requirements.txt

test:
  override:
    - pwd ~
    - ifconfig
    - echo HelloWorld
    - exit 0
```

```text:requirements.txt
Flask==0.10.1
Flask-Script==2.0.5
pytz==2015.7
redis==2.10.5
requests==2.9.1
six==1.10.0
SQLAlchemy==1.0.11
gunicorn==19.4.5
pytest==2.8.5
```


##### 7. バックグラウンドでrunserverする
**バックグラウンドで実行する理由は、並列(Parallel)実行させないとrunserverの終了待ちで処理が止まって試験が終わらなくなるからです。**

pythonスクリプトをCircleCI上で稼働させるためには、chmodでの権限の付与とPYTHONPATHの設定が必要です。Flaskなのにmanage.pyなのはFlask-Scriptでカスタマイズした影響です。Django経験者にはFlask-Script便利。サーバが稼働しているかの疎通確認は`test:override:`内でcurlコマンドを書くと便利です。

```yaml:circle.yml
machine:
  python:
    version: 3.5.0

dependencies:
  pre:
    - chmod -R 777 ./example
    - pip install -r ./requirements.txt
    - export PYTHONPATH="/home/ubuntu/flask_template/example/application"
    - python ./application/manage.py runserver:
          background: true
    - sleep 5

test:
  override:
    - pwd ~
    - ifconfig
    - echo HelloWorld
    - curl http://127.0.0.1/example
    - exit 0
```

##### 8. テストを通す
py.testでテスト書きます。HttpStatusを確認するだけの単純なものです。今回はサンプルなので内容は同じ

■ py.test用のコード

```py3:test_example.py
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import requests


def test_example():
    host = "127.0.0.1:5000"
    url = 'http://{}/example/'.format(host)
    print(url)
    response = requests.get(url)
    print(response.text)
    assert response.status_code == 200
    assert "Error" not in response.text

```

```yaml:circle.yml
machine:
  python:
    version: 3.5.0

dependencies:
  pre:
    - chmod -R 777 ./example
    - pip install -r ./requirements.txt
    - export PYTHONPATH="/home/ubuntu/flask_template/example/application"
    - python ./application/manage.py runserver:
          background: true
    - sleep 5

test:
  override:
    - pwd ~
    - ifconfig
    - echo HelloWorld
    - curl http://127.0.0.1/example
    - py.test ./example/tests/test_example.py
    - exit 0
```

commitしてテストが通れば作業完了

##### 9. 結果をHipChatに通知させる
Project Settings > Notifications page.　で通知先を設定できます。[公式ドキュメントのnotify](https://circleci.com/docs/configuration#notify)を読むと判りやすいかと

■ 通知された
![スクリーンショット 2016-02-26 20.47.16.png](https://qiita-image-store.s3.amazonaws.com/0/65312/c8a02af3-839d-9fa6-8236-9e0d0b549289.png)


## この記事で扱っていない範囲
mysqlは試していないので今後試したいです。[公式ドキュメントのデータベース設定](https://circleci.com/docs/configuration#database)

# CircleCI触ってみた感想
最初は理屈がわからず学習コスト重くはじめの一歩が大変でした。公式ドキュメントが充実していて大変良いと思いました。PythonのWebフレームワークをテストするという限定的な用途ですと、誰かが頑張って設定ファイル書けば、それを参考にして量産できそうだなと感じました。