Vagrant + Docker + Python3でTwitter APIを叩いてみる


環境構築

ドットインストールのdockerをそのままなぞっています。

VM作成

作業ディレクトリ(MacOS)は/user/Myvagrant/Dockerとしました。
DockerはUbuntuサポートなので、VMはUbuntu14.04(trusty)64にしようと思います。
Vagrantbox.esに飛んでURLをコピーします。
vagrant box add trusty64 (コピーしたURL)とすればboxが作られます。
Dockerディレクトリでvagrant initしましょう。Vagrantfileが作られるので編集します。
今回はip:192.168.55.44
としました。

vagrant up
vagrant ssh

でOK。
以下は全てVM内で行っています。

Dockerインストール

公式ドキュメント

sudo apt-get update
sudo apt-get install \
  apt-transport-https \
  ca-certificates \
  curl \
  software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
sudo add-apt-repository \
  "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) \
  stable"
sudo apt-get update
sudo apt-get install docker-ce

Dockerがインストールされます。昔は面倒なことをせずともsudo apt-get install docker.ioでよかったらしいのですが、開発スピードが速いのでめまぐるしく変わりますね。

試しに動かす

sudo docker run hello-world

Hello,Docker!が表示されたので良さそう。

Twitterサービスを作る

コンテナ: CentOS6
やること: Twitter APIから投稿する

python3環境のcentOS6を作りたい

Docker上のCentOSにPython3と、関連ライブラリpip, virtualenvとフレームワークDjango, bottle, Flaskのインストール!これらをまとめたDockerfile付き!
これを使いました。Anacondaを入れると何が入ってるかわからなくなるけど、Dockerfileで逐一確認すればそれもなくなるのが便利です。

ディレクトリ構成

1サービス1ディレクトリを心がけました。

home
  │   
  ├── python
  │   └── Dockerfile #python2環境を作ったDockerfile
  └── twitter
      ├── Dockerfile #tweetするためのDockerfile
      └── tweet.py

Dockerfileはリンク先のものほぼそのままです。

Dockerfile
# OSはCentOS6
FROM centos:centos6

# 各パッケージをインストール
# pipやvirtualenvインストールも想定しています。
RUN yum -y update
RUN yum -y groupinstall "Development Tools"
RUN yum -y install \ 
           kernel-devel \
           kernel-headers \
           gcc-c++ \
           patch \
           libyaml-devel \
           libffi-devel \
           autoconf \
           automake \
           make \
           libtool \
           bison \
           tk-devel \
           zip \
           wget \
           tar \
           gcc \
           zlib \
           zlib-devel \
           bzip2 \
           bzip2-devel \
           readline \
           readline-devel \
           sqlite \
           sqlite-devel \
           openssl \
           openssl-devel \
           git \
           gdbm-devel \
           python-devel 

# Python3.5.2をインストール
# Python3.5.2をダウンロード
WORKDIR /root
RUN wget https://www.python.org/ftp/python/3.5.2/Python-3.5.2.tgz
RUN tar xzvf Python-3.5.2.tgz

# makeでインストール
WORKDIR ./Python-3.5.2
RUN ./configure --with-threads
RUN make install

# pipインストール(最新版)
RUN wget https://bootstrap.pypa.io/get-pip.py
RUN python get-pip.py

# readlineインストール
RUN pip install readline

# virtualenvインストール
RUN pip install virtualenv

# Djangoインストール(今回はしてません)
# RUN pip install django

# おまけ
# Django以外のフレームワークインストール
# bottleインストール
# RUN pip install bottle

# Flaskインストール
# RUN pip install Flask

WORKDIR /root
CMD ["/bin/bash"]

このままだとインストールされただけで、containerにpython3環境ができたわけではないので、pyenvを使ってpython3を使えるようにします。

とりあえず、

sudo docker build -t python2/env

として、今のpython2環境を保存しました。

sudo docker run -it python2/env
[root@66efa67f343a root]#

containerには入れたところで、pyenvを入れていきます。
これも先ほどのリンクと全く同じです。
container内で、

[root@66efa67f343a root]# git clone https://github.com/yyuu/pyenv.git /root/.pyenv
[root@66efa67f343a root]# vi /etc/skel/.bash_profile
[root@66efa67f343a root]# source /etc/skel/.bash_profile
[root@66efa67f343a root]# pyenv install 3.5.2
[root@66efa67f343a root]# python -V
Python3.5.2
bash_profile
#追加
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

これでpython3環境ができたので、exitで一旦抜けたあとに

sudo docker commit {コンテナID} python3/env

とすれば、python3のイメージが完成!と思ったんですが…

runしたときに、bash_profileが反映されない

python3/envをrunしてすぐにバージョンを確認するとpython2.6.6って出ました。source /etc/skel/.bash_profileとすればpython3環境になるので、変更は保存されているようなのですが…よくわかりませんでした。
コンテナに入る時には毎回source /etc/skel/.bash_profileを最初にすること、Dockerfileをpython3/envを継承して作るときは

RUN ["/bin/bash", "-c" ,"source /etc/skel/.bash_profile, \
  && {python3でやりたい処理} \
"]

みたいに毎回やらないといけないので面倒なのですがこれ以外に方法がわからなかったです。
とりあえずpython3環境にする方法はわかりました。

TwitterAPIを叩く

参考
Python で Twitter API にアクセス
これをやります。
リンク先のやり方にしたがってConsumer Key,Consumer Secret, Access Token, Access Token Secretを調べます。Consumer~はアプリごと、Access~はアカウントごとに取得します。Access~がすぐにわかるのは自分のアカウントなので自分のでやっちゃいました。

ツイートを投稿

tweet.py
from requests_oauthlib import OAuth1Session
import json

CK = 'Consumer Keyを入力'                             # Consumer Key
CS = 'Cousumer Secretを入力'         # Consumer Secret
AT = 'Access Tokenを入力' # Access Token 
AS = 'Access Secretを入力'         # Accesss Token Secert

# ツイート投稿用のURL
url = "https://api.twitter.com/1.1/statuses/update.json"

# ツイート本文
params = {"status": "dockerを使ったTwitterの自動投稿の練習中"}

# OAuth認証で POST method で投稿
twitter = OAuth1Session(CK, CS, AT, AS)
req = twitter.post(url, params = params)

# レスポンスを確認
if req.status_code == 200:
    print ("OK")
else:
    print ("Error: %d" % req.status_code)

これでpython3環境で動かせばいけるはず、なのでツイートを投稿するコンテナを作りましょう。

Dockerfile
FROM python3/env
MAINTAINER 名前 <メールアドレス>

ADD ./tweet.py /home
WORKDIR /home

RUN ["/bin/bash", "-c", " \
      source /etc/skel/.bash_profile \
      && pip install requests requests-oauthlib \
    "]

CMD ["/bin/bash"]

twitterディレクトリに移動して、

sudo docker build -t twitter:tweet .

とすれば、twitter:tweetイメージが作成されます。これをrunすればいけそう…

はいエラー

結果エラーでした。エラーをプリントすると,Timestamp out of bounds - code:135とあったので、調べたところ、Containerの時刻設定とTwitterの時刻設定がずれていたことが原因なようです。ここでかなりつまづきました。
結果、Box自体の時刻がずれていたのでVagrantfileを書き換えて、ホスト(自分の場合MacOS)の時刻をとってくるようにしました。
参考
vagrantで時刻がおかしい場合の対処法
上の通りやったらうまく治りました。

無事に投稿に成功しました…長い。