fabricを使ってwebサイト(django)の環境設定やdeployを自動化した
自分のwebサイトのapacheの設定やら何やら忘れてしょうがないので、この機会にfabricで環境設定やらdeployなりの手順をコードに落として自動化することにした。
サーバはさくらVPSのCent OS 6.8。
以下メモとして。
前作業(サーバの初期設定)
サーバを新しくしたので最初から。こういうとこもコード化できたらいいが、とりあえず手作業でやった。
- rootユーザのパスワードを変更
- 一般ユーザを追加、sudo権限を与える
- サーバアクセス用のssh鍵をlocalで生成し、scpでサーバに送る。適切なパーミッションに設定する
- 公開鍵認証でのみログインできるようにssh接続設定を変更
- local PCでssh configに新しいサーバの情報を追加し、ログインしやすくする(fabricでも使う)
- ファイアウォールの設定
作業ログ
rootでserverにlogin
# root passwd change, add general user ## root login ssh root@hoge.sakura.ne.jp
rootのpassword変更、一般userの追加
# rootのパスワード変更 passwd # 一般ユーザの追加、パスワード変更 useradd hogeuser passwd hogeuser
一般userにsudo権限を与える
# 一般ユーザにsudo権限を与える ## login as root ssh root@hoge.vs.sakura.ne.jp usermod -G wheel hogeuser visudo
wheelにすべての権限を与えるよう変更
## Allows people in group wheel to run all commands
%wheel ALL=(ALL) ALL
localでssh鍵を生成。scpでserverに送る。
ssh鍵以外のloginを禁止するように/etc/ssh/sshd_config
を変更する
# generate ssh ssh-keygen -t rsa -C sakura_2nd_server -f ~/.ssh/id_rsa_sakura2 # scp ssh-key to server scp ~/.ssh/id_rsa_sakura2.pub hogeuser@hoge.vs.sakura.ne.jp: # login to server as general user ssh hogeuser@hoge.vs.sakura.ne.jp
scpでserverに送った公開鍵のpermissionを正しく設定する
mkdir .ssh chmod 700 .ssh cat id_rsa_sakura2.pub >.ssh/authorized_keys chmod 600 .ssh/authorized_keys rm id_rsa_sakura2.pub # change sudo ssh setting sudo vim /etc/ssh/sshd_config
公開鍵認証以外でssh接続できないようにする
#Port22 →Port**** #PermitRootLogin yes →PermitRootLogin no PasswordAuthentication yes →PasswordAuthentication no
sshd_configをreloadさせる
sudo /etc/rc.d/init.d/sshd reload
localから秘密鍵以外でloginできないか確認する
# loginできないのを確認 ssh root@hoge.vs.sakura.ne.jp ssh hogeuser@hoge.vs.sakura.ne.jp # loginできるのを確認 ssh hogeuser@hoge.vs.sakura.ne.jp -i ~/.ssh/id_rsa_sakura2 # sshd_configを編集 emacs ~/.ssh/config
新しいserverの情報をssh configに追加
Host sakura2
HostName hoge.vs.sakura.ne.jp
Port 22
IdentityFile ~/.ssh/id_rsa_sakura2
User hogeuser
loginできるか確認
ssh sakura2
あとはファイアウォールの設定など
(参考)
- 作者: 一戸英男
- 出版社/メーカー: 日本実業出版社
- 発売日: 2005/04/07
- メディア: 単行本
- 購入: 22人 クリック: 524回
- この商品を含むブログ (29件) を見る
ここからはfabricで
fabfile
接続先サーバの設定
自分しか利用者がいないので、~/.ssh/config
の情報を再利用した。
from fabric.api import * env.use_ssh_config = True env.hosts = ['sakura2']
これで自動的にfabricが~/.ssh/config
を読み込んでくれ、'sakura2'という名のhostのhost name, port, 公開鍵, user nameなどを使ってくれる。
ネイティブのSSH configファイルの活用 (fabric公式ドキュメント)
nginxのinstall
nginxの公式にもあるように、yum install nginxでinstallされるnginxは古かったりするので、nginx yum repositoryを追加する。
from fabric.api import * from fabric.contrib.files import upload_template, exists, append yum_repo_folder = '/etc/yum.repos.d' nginx_version = '1.10.1' nginx_dir = 'nginx-{}'.format(nginx_version) nginx_url = 'http://nginx.org/download/{}.tar.gz'.format(nginx_dir) nginx_conf_path = '/etc/nginx/conf.d/arieee.conf' def add_nginx_yum_repo(): # local PCのrepoファイルをサーバに送る with lcd(LOCAL_APP_FOLDER): # mac local template = 'conf/nginx.repo' upload_template(template, yum_repo_folder, use_sudo=True) def get_nginx(): add_nginx_yum_repo() sudo('yum -y update') sudo('yum -y install nginx') def start_nginx(): sudo('/usr/sbin/nginx') def reload_nginx(): sudo('/usr/sbin/nginx -s reload') @task def install_nginx(): get_nginx() start_nginx()
[nginx] name=nginx repo baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck=0 enabled=1
python環境(python, pip, virtualenv)のinstall
pyenvでinstallしたpythonはどのユーザからも共通して使ってほしいので、~/.bash_profile
ではなく、/etc/profile.d
下に置いた。(他の方法あるのかな?)
def install_python_dev(): sudo('yum -y update') sudo('yum -y install python-devel') # pyenvでのpython installに必要なlibrary # https://github.com/yyuu/pyenv/wiki/Common-build-problems sudo('yum -y install zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel') def install_pyenv(): sudo('git clone https://github.com/yyuu/pyenv.git /usr/local/.pyenv') # システム全体にpythonのversionを適用したいので、/etc/profile.d/ に設定を書き込む sudo('echo \'export PYENV_ROOT="/usr/local/.pyenv"\' >> /etc/profile.d/pyenv.sh') sudo('echo \'export PATH="$PYENV_ROOT/bin:$PATH"\' >> /etc/profile.d/pyenv.sh') sudo('echo \'eval "$(pyenv init -)"\' >> /etc/profile.d/pyenv.sh') sudo('exec $SHELL -l') sudo('pyenv install 2.7.11') sudo('pyenv global 2.7.11') sudo('pyenv rehash') def install_pip(): with cd('/tmp'): run('wget https://bootstrap.pypa.io/get-pip.py') sudo('python get-pip.py') # upgrade pip sudo('pip install -U pip') # install uwsgi, virtualenv sudo('pip install uwsgi') sudo('pip install virtualenv') @task def setup_python_env(): install_python_dev() install_pyenv() install_pip()
django, uwsgiのための準備
- uwsgi用のwwwユーザを作成
- uwsgi用のlogフォルダ、runフォルダを作成
- uwsgiをemperor modeのための設定ファイルフォルダを作成 (/etc/uwsgi/vassals)
- django application用のvirtualenvを作成
/var/run/uwsgiは、将来的にuwsgiのプロセスをプログラムから起動・終了したりするために、プロセスIDのファイルを格納するフォルダとして使う。
def create_www_user(): # cent os doesn't have www-data sudo('groupadd www-data') sudo('useradd -d /home/www-data -g www-data -r -s /sbin/nologin www-data') def setup_uwsgi_emperor(): sudo('mkdir -p /var/log/uwsgi') sudo('mkdir -p /var/run/uwsgi') sudo('chown www-data:www-data /var/log/uwsgi') sudo('chown www-data:www-data /var/run/uwsgi') # create a directory for the vassals sudo('mkdir -p /etc/uwsgi/vassals') def setup_virtualenv(): with cd(BASE_FOLDER): run('virtualenv venv_arieee')
nginx, wsgiの設定ファイルのupload
nginx, wsgiの設定ファイルについては、以下を参考にした。
- Setting up Django and your web server with uWSGI and nginx (uWSGI公式ドキュメント)
- How to use Django with uWSGI (django公式ドキュメント)
def upload_nginx_conf(): with lcd(LOCAL_APP_FOLDER): # mac local template = 'conf/nginx.tmpl' # local file context = {'app_folder': APP_FOLDER, 'remote_static_folder':REMOTE_STATIC_ROOT} upload_template(template, nginx_conf_path, context, use_sudo=True) # delete existing default.conf if exists('/etc/nginx/conf.d/default.conf'): sudo('mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.org') def upload_uwsgi_conf(): if not exists(os.path.dirname(uwsgi_ini_path)): run('mkdir -p {}'.format(os.path.dirname(uwsgi_ini_path))) with lcd(LOCAL_APP_FOLDER): # mac local template = 'conf/arieee_wsgi.ini.tmpl' context = {'app_folder': APP_FOLDER, 'base_folder': BASE_FOLDER, 'django_folder': DJANGO_FOLDER} upload_template(template, uwsgi_ini_path, context, use_sudo=True) # symlink from the default config directory to your config file sudo('ln -sf {} /etc/uwsgi/vassals/'.format(uwsgi_ini_path)) reload_nginx() def run_uwsgi_emperor(): sudo('uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data')
# arieee_uwsgi.ini file [uwsgi] # Django-related settings # the base directory (full path) chdir = %(django_folder)s # Django's wsgi file module = arieee.wsgi # the virtualenv (full path) home = %(base_folder)s/venv_arieee # process-related settings # master master = true # maximum number of worker processes processes = 1 # the socket (use the full path to be safe socket = /var/run/uwsgi/arieee.net.sock # pid pidfile = /var/run/uwsgi/arieee.net.pid # log daemonize = /var/log/uwsgi/arieee.net.log # ... with appropriate permissions - may be needed chmod-socket = 666 # clear environment on exit vacuum = true
# the upstream component nginx needs to connect to upstream django { server unix:///var/run/uwsgi/arieee.net.sock; # server 127.0.0.1:8001; } # configuration of the server server { # the port your site will be served on listen 80; # the domain name it will serve for server_name .arieee.net; charset utf-8; # max upload size client_max_body_size 75M; # Django media location /media { alias %(app_folder)s/arieee/media; } location /static { alias %(remote_static_folder)s; } # Finally, send all non-media requests to the Django server. location / { uwsgi_pass django; include %(app_folder)s/uwsgi_params; } }
deploy
@task def first_deploy(): create_www_user() setup_uwsgi_emperor() setup_virtualenv() deploy() @task def deploy(): with settings(warn_only=True): if run("test -d {}".format(APP_FOLDER)).failed: run("git clone {} {}".format(GIT_REPOSITORY, APP_FOLDER)) with cd(APP_FOLDER): run("git pull") # install needed python libraries with prefix('source {}/bin/activate'.format(VENV_FOLDER)): with cd(APP_FOLDER): run('pip install -r requirements.txt') # uplodad nginx conf upload_nginx_conf() # uwsgi upload_uwsgi_conf() setup_uwsgi_emperor() run_uwsgi_emperor()
以上のfabricのtaskを以下のように実行
fab install_nginx setup_python_env first_deploy
めちゃくちゃ疲れた。。dockerとか使ったらもっと楽になるのかな? 自動化するのは楽しいけどあんまり生産的じゃないので、こういう作業はできるだけ最小化したい。。 あとwsgi, uwsgiがまだあんまりわかっていないのでもうちょっと勉強したい。
[参考]
amazonで見ている本にkoboの価格を表示するchrome拡張を作りました
去年の秋からコツコツと所有本を電子化してます.なので新しい本を買う時もできるだけ電子書籍版の方を買いたい. そこで電子書籍版があるかどうか,あったらどこが一番安いかをamazon / kobo (rakuten books) の両方探したりするのですが,まあめんどいです.
ということで,amazonのページにkoboの価格とリンクを表示するchrome拡張を作りました. 自分用に作ったら思ったより便利だったのでchrome storeで公開しています.
こだわりポイント
あくまでamazonのページデザインに沿って表示するので目障りになりません.
しかもkoboの価格がkindleよりも高ければ灰色に,
安ければ赤色に,
など細かい謎の気配りをしてくれます.できるやつです.
ちなみに最初は楽天ぽく表示するバージョンも作ってみて個人的には気に入ってたんですが, 友達に見せたところすごい顔されたのでボツになりました.これです.
いいですね〜〜〜
だって値段高いのにkoboの方を買いたくなりませんか
なりませんか.すみません.
どんな人に便利か
- kindle/koboの両方使っている人
- とにかく安く本が読みたい人
国内2大電子書籍プラットフォームであろうkindleとkoboですが,やはり国内の本の品揃え・価格に関してはkindleの方が現時点では優れていると思います.
しかし,たまにkoboしか取り扱っていなかったり,koboの方が安い時があります.
このchrome拡張はamazonのページ内でkoboの情報を表示するので,そのような場合でも誤って紙の本や高いkindle版を買うことを避けられます.
- 洋書を読む人
koboが強いのが技術書などの洋書です.
洋書にはkoboしか取り扱いがない本,koboの方が大幅に安い本が結構あります.
よく洋書を買う人は入れても損はないと思います.
ということでKoboでは、この価格 - Chrome Web Store よければ使ってみてください.
chrome拡張の作り方
以下技術情報.
今回chrome拡張初めて作りましたが,意外に(仕組みは)簡単でした.
まず一つのフォルダを用意し,その中にmanifest.jsonというファイルを置いて,プログラムのメタ情報を記述します
{ "name": "Koboでは、この価格", "version": "1.0.3", "manifest_version":2, "description":"amazonで見ている本のkoboでの価格を表示します", "icons":{ "16":"images/shelf16.png", "64":"images/shelf64.png", "128":"images/shelf128.png" }, "permissions":[ "http://www.amazon.co.jp/*" ], "content_scripts":[ { "css":["style.css"], "matches":["http://www.amazon.co.jp/*"], "js":["jquery.js","contentscript.js"] } ], "web_accessible_resources": ["images/ajax-loader.gif"] }
作ったchrome拡張のタイトル・説明や,アイコン,css, jsの場所など
permissionsはユーザーのどの情報にアクセスするのか明記するところです.
今回はユーザーが見ているamazonのページ上の,本のタイトルや著者の情報にアクセスしているので "matches":["http://www.amazon.co.jp/*"]
と書いています.
もしユーザーのchrome上のbookmarkとかにアクセスするのであれば,それも書きます.
あとはゴリゴリcontentscript.jsで処理を記述すればいいだけです. js慣れてないから結構時間かかった...
koboでの価格を取得するのには 楽天API( 楽天ウェブサービス: API一覧 )を用いています.
タイトルや著者をqueryに含めて投げれば,その本の価格等が取得できます.
koboのセール情報とかポイント情報とかも取得できれば,それを含めてもっと楽天ぽくできるのになあ