togatttiのエンジニアメモ

過度な期待はしないでください.

SeleniumサーバをDockerで構築する

SeleniumサーバをDockerコンテナとして構築する。

すでにGitHubdocker-seleniumというプロジェクトが出ているが、

今回は日本語環境で利用したかったので、ゼロから作り直した。

github.com

使い方

$ git@github.com:kentatogashi/docker-selenium-ja.git
$ cd docker-selenium-ja
$ docker build -t 'kentatogashi/docker-selenium-ja' .
$ docker run -dt -p 4444:4444 -p 5901:5901 kentatogashi/docker-selenium-ja

後記

デスクトップには、xfce4を使用していて、VNCでもつなぐことができる。

ちなみに、MacOSだと便利なことに、openコマンドで、簡単に立ち上げられる。

$ open vnc://selenium@192.168.99.100:5901

entrypointでは、vncserverの起動とXサーバを経由してSeleniumを起動する。

ただ、vncserver起動時にパスワードを対話形式で聞かれてしまうので、少しハマった。

結果的に、vncpasswdで、パスワードを事前に作成しておいて、それをコンテナに置くようにした。

Dockerfileには、こんな記述を書いた

# VNC Password
RUN mkdir /root/.vnc
ADD .vnc/passwd /root/.vnc/passwd
RUN chmod 600 /root/.vnc/passwd

コマンドラインの結果をデスクトップに出力するために、 DISPLAYをきちんと指定が必要なのは初めて知った。

例えば、コマンドラインから、firefoxを実行する場合

$ DISPLAY=:1 firefox

こうしておくと、デスクトップで開ける。

追記(2016/03/19)

Docker Hubに、登録したので、docker pull できる。

https://hub.docker.com/r/kentatogashi/docker-selenium-ja/

参考

DockerのUbuntu14.10の日本語化環境イメージを作成(Ubuntu) | BROKENDISH

CentOS/Ubuntu Linuxで、Oracle JDK 8をインストールしたDockerイメージを作る - CLOVER

作業用Bashスクリプトのテンプレート

よく自分で書く作業用Bashスクリプトのテンプレートを残す。

気にかけていることは、

  • -e オプションで、エラー時点で処理終了
  • エラー時は、$LINENOで、該当行数出力
  • -x オプションで、デバッグ

あたりは、必ずできるようにしてる。

余裕がある時は、

  • 出力を着色

テンプレート

#!/usr/bin/env bash
# template.bash
set -e
[ -n "$DEBUG" ] && set -x

help() {
  echo "$0 some args"
  echo "some help"
  exit 1
}

if [ -t 1 ]; then
  green_color="\e[1;32m"
  red_color="\e[1;31m"
  reset="\e[0m"
else
  color=""
  reset=""
fi

indent_output() {
  while read -r data; do
  printf " ${green_color} | ${reset}  %s\n" "$data"
  done
}

print_colored() {
  printf "${green_color}%s${reset}\n" "$1"
}

err_exit() {
  printf "${red_color}[ERROR] %s${reset} at line ${LINENO}\n" "$@"
  exit 1
}

for arg; do
  case "$arg" in
    --help) help ;;
      * ) 
  esac
done

print_colored "Updating some software..."
echo -e "hoge\nbar\nfoo" | indent_output
err_exit "failed zannen"

exit 0

出力は、

f:id:togattti1990:20160313115853p:plain

デバッグ時は、

DEBUG=1 bash template.bash

とかで、叩くとデバッグできる。

JenkinsをDocker環境にリプレイスする

JenkinsサーバをDockerコンテナとしてリプレイスする手順を示す。

前提

Dockerコンテナとして、Jenkinsを稼働

docker-machine を使いDockerホストを立ち上げる。

ドライバーはVirtualBoxを使う。

$ brew install docker-machine
$ docker-machine create --driver virtualbox dev
$ docker-machine ssh dev

IPは、後々使うので、メモしておく。

docker@dev:~$ ifconfig eth1 | grep 'inet addr'
          inet addr:192.168.99.100  Bcast:192.168.99.255  Mask:255.255.255.0

Jenkinsサーバをコンテナとして、起動させる。

この記事が参考になった。

knjname.hateblo.jp

Jenkinsのデータを永続させるためのディレクトリをDockerホストに作成して、起動させる。

$ mkdir /var/lib/jenkins
$ docker run -p 8080:8080 -v /var/lib/jenkins/:/var/jenkins_home jenkins

起動できると、http://192.168.99.100:8080 でブラウザからアクセスできる。

確認したら、Ctrl+Cで、抜ける。

Jenkinsのバックアップデータ移行

${JENKINS_HOME} は、jenkinsのホームディレクトリのパスを示す。

コンテナにはいる。

$ docker run -v /var/lib/jenkins/:/var/jenkins_home -it jenkins bash

Jenkinsサーバのバックアップデータの移動手順は、割愛する。

Dockerコンテナにリプレイスする際に、以下のバックアップデータが必要なので、Dockerコンテナの /tmp に配置する。

  • ThinBackupプラグインで、作成する FULL-${yyyy}-${mm}-${dd}_${HH}-${MM}のディレクトリ
  • ${JENKINS_HOME}/plugins ディレクトリ

データをDockerコンテナ内の ${JENKINS_HOME} に展開する。

$ cp -pr /tmp/FULL-2016-03-08_12-00/* /var/jenkins_home/
$ cp -pr /tmp/plugins /var/jenkins_home/

以上で、データ移行が完了。

ただし、過去のビルド履歴が残っている場合、ビルド時にエラーが出る。

SEVERE: Unexpected executor death
java.lang.IllegalStateException: /var/jenkins_home/jobs/test_job/builds/2 already existed;

この場合は、ビルド履歴は削除しておく必要がある。

$ rm -rf /var/jenkins_home/jobs/test_job/builds
$ echo '1' > /var/jenkins_home/jobs/test_job/nextBuildNumber

コンテナをCtrl+Cで抜けてから、デーモンとして、Jenkinsを起動させる。

$ docker run -d -p 8080:8080 -v /var/lib/jenkins/:/var/jenkins_home jenkins

以上で、リプレイス完了。

参考

kakakikikekeのブログ: Jenkinsでビルド履歴をすべて削除する方法

2分でWordPressをセットアップする(Docker編)

Dockerで、WordPressのセットアップが2分でできた。

ApacheMySQLPHP等のミドルウェアも、Docker コンテナで完結する。

コンテナは、Docker Hub にある、WordPressMySQLの公式版を使う。

準備
$ docker-machine ssh dev
$ cat setup_wp.sh 
#!/bin/sh
docker pull wordpress &
docker pull mysql &
wait
docker run --name mysql -e MYSQL_ROOT_PASSWORD=mysql -d -p 3306:3306 mysql
docker run --name my-wordpress --link mysql:mysql -p 80:80 -d wordpress
$ chmod 755 setup_wp.sh
スタート
$ time ./setup_wp.sh 
Using default tag: latest
Using default tag: latest
latest: Pulling from library/mysql
Digest: sha256:7665507aea0785e89e51c193381ec33ec8662d02cd5c995b9f31e432fcaaa541
Status: Downloaded newer image for mysql:latest
latest: Pulling from library/wordpress
(省略)
real    1m 55.88s
user    0m 0.35s
sys 0m 0.26s

これで、Dockerホストをブラウザで、叩くとWordPress画面が表示される。

2分でおわるとか、すごい。。

ちなみに、wifiモバイルルータで、下りは6Mbpsくらいのときに実施した。

Ansibleで、クライアントPCのファイルの存在チェック

Ansibleを使うとき、クライアント側の実行結果をトリガーにして何かする場合、 local_actionとregisterモジュールを組み合わせれば良い。

クライアントPC側で、あるファイルの存在を確認するためには、statモジュールを使う。

使用例

一般的なAnsibleのディレクトリ構造が以下のようにあり、commonは、

config.ymlをリモートマシンに送るrolesである。

tree .
.
├── inventory
│   └── hosts
├── roles
│   └── common
│       ├── files
│       │   └── config.yml
│       └── tasks
│           └── main.yml
└── site.yml

roles/common/tasks/main.yml の中身は次のように書いた。

ここでは、config.ymlが存在していれば、ファイルをリモートに転送して、

無ければ、ファイルの転送をスキップするように振り分ける。

# roles/common/tasks/main.yml
- name: check config.yml exists in local
  local_action: stat path="roles/common/files/config.yml"
  register: file
  ignore_errors: True

- name: copy config.yml to remote
  copy: src=config.yml dest=~/config.yml
  when: file.stat.exists

config.ymlがある場合

ansible-playbook -i inventory/hosts site.yml 

PLAY ***************************************************************************

TASK [setup] *******************************************************************
ok: [***.***.***.***]

TASK [common : check config.yml exists in local] *******************************
ok: [***.***.***.***]

TASK [common : copy config.yml to remote] **************************************
changed: [***.***.***.***]

PLAY RECAP *********************************************************************
***.***.***.***            : ok=3    changed=1    unreachable=0    failed=0

config.ymlがない場合

ansible-playbook -i inventory/hosts site.yml 

PLAY ***************************************************************************

TASK [setup] *******************************************************************
ok: [***.***.***.***]

TASK [common : check config.yml exists in local] *******************************
ok: [***.***.***.***]

TASK [common : copy config.yml to remote] **************************************
skipping: [***.***.***.***]

PLAY RECAP *********************************************************************
***.***.***.***            : ok=2    changed=0    unreachable=0    failed=0