LimeSurvey
OSSのWebアンケートシステム
多機能で見た目も素敵なので活用することにした。
いつものようにコンテナで使おうと思って、今回はDockerfileと久々にansible-containerで作ることにした。
結果として3つの自動化コードを作った。
- Dockerfile
- ansible-container 用 Role
- Dockerfile からの ansible-container へマイグレーションした Role
いずれも、1,2回コマンド叩いてLimeSurveyが利用できるようになる。(コンテナイメージ作成、コンテナの起動)
動作環境
推奨の下記の環境で作ることにした。(Webに記載あり)
- nginx 1.4.6
- php 5.6.x
- with php-fpm, mbstring, gd2 with freetype, imap, ldap, zip, zlib and databse drivers
- mysql 5.5.50
実際に作った時の環境は以下
- Docker : 17.12.0-ce
- Base Image : CentOS 7.4.1708
- Ansible : 2.4.2.0
- Ansible-Container : 0.9.2
Package | Version |
---|---|
nginx | 1.13.9 |
php | 5.6.33 |
Mariadb | 5.5.56 |
Install Ansible and Ansible-Container
# yum install epel-release
# yum update
# yum install ansible
# yum install python-pip
# pip install --upgrade setuptools
# pip install ansible-container[docker,k8s]
1. Dockerfile
下記のようなDockerfileを作成。
# Docker file for Lime Survey
FROM centos:7
MAINTAINER Tk
ARG URL=http://www.d-ip.jp/download/images/limesurvey2.73.0+171219_ja_dip.tar.gz
# Install Nginx
COPY nginx.repo /etc/yum.repos.d/
RUN yum -y update && yum -y install nginx
# Config Nginx for php
COPY default.conf /etc/nginx/conf.d/
# Install PHP 5.6
RUN yum -y install epel-release && yum -y update
RUN rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
RUN yum -y install --enablerepo=remi,remi-php56 php-fpm php-mbstring php-gd php-imap php-ldap php-zip php-zlib php-mysqlnd php-xml
# Config php-fpm
RUN sed -i -e "s/^user\s=\sapache$/user = nginx/g" /etc/php-fpm.d/www.conf
RUN sed -i -e "s/^group\s=\sapache$/group = nginx/g" /etc/php-fpm.d/www.conf
RUN chgrp -R nginx /var/lib/php/{session,wsdlcache}
# Install Mariadb
RUN yum -y install mariadb-server
# Config Mariadb
RUN mysql_install_db --user=mysql --ldata=/var/lib/mysql/
# Download Limesurvey
RUN mkdir -p /var/www
RUN curl -L -o /tmp/limesurvey.tar.gz ${URL}
RUN tar zxf /tmp/limesurvey.tar.gz -C /var/www && \
mv /var/www/* /var/www/survey && \
chown -R nginx.nginx /var/www/survey
# Set startup
COPY start.sh /root/
CMD ["/root/start.sh"]
補足
- phpのパッケージはドキュメントに記載のなかったものを追加
- nginx.repo 用意
- default.conf 用意
- mariadb,ngnix,php-fpmを順に起動するシェル準備(start.sh)
- LimeSurveyインストーラで事前チェックで「セッション書き込み」にアラートが出たため、
/var/lib/php/{session,wsdlcache}
の属性変更
Build & Run
# docker build -t tksarah/limesurvey
Sending build context to Docker daemon 8.192kB
Step 1/19 : FROM centos:7
---> ff426288ea90
(略)
Successfully built af65374fe68f
Successfully tagged tksarah/limesurvey:latest
# docker run -id --name lime -p 80:80 tksarah/limesurvey
2. Ansible-Container Role
# mkdir limesurvey
# cd limesurvey
# ansible-container init
Ansible Container initialized.
# ls
ansible-requirements.txt ansible.cfg container.yml meta.yml requirements.yml
# for x in limesurvey nginx mariadb php start; do ansible-galaxy init $x; done
- limesurvey was created successfully
- nginx was created successfully
- mariadb was created successfully
- php was created successfully
- start was created successfully
ロール作成
それぞれのロールを作る
limesurvey role
あまり美しくないが。。。Renameのところ。
---
ROOT_DIR: /var/www
SERVICE_DIR: /var/www/survey
URL: "http://www.d-ip.jp/download/images/limesurvey2.73.0+171219_ja_dip.tar.gz"
---
- name: Create Service Directory
file: path={{ SERVICE_DIR }} owner=nginx group=nginx recurse=yes state=directory
- name: Download Limesurvey
get_url: url={{ URL }} dest=/tmp/limesurvey.tar.gz
- name: Unarchive
unarchive: src=/tmp/limesurvey.tar.gz dest={{ ROOT_DIR }} remote_src=yes
- name: Rename
shell: mv {{ ROOT_DIR }}/*/* {{ SERVICE_DIR }}
args:
creates: "{{ SERVICE_DIR }}/index.php"
- name: Change attribute
file: path={{ ROOT_DIR }} owner=nginx group=nginx recurse=yes state=directory
- name: Cleanup
file: path=/tmp/limesurvey.tar.gz state=absent
---
URL: "https://github.com/LimeSurvey/LimeSurvey/archive/3.4.1+180221.tar.gz"
nginx role
- templatesにdefault.conf.j2配置
---
ROOT_DIR: "/var/www/survey"
SERVER_NAME: "localhost"
- name: Add repository
yum_repository:
name: nginx
description: Nginx Repo
baseurl: http://nginx.org/packages/mainline/centos/7/$basearch/
- name: Install nginx
yum: name=nginx state=latest disable_gpg_check=yes
- name: Config defalt.conf
template: src=default.conf.j2 dest=/etc/nginx/conf.d/default.conf
mariadb role
- name: Install Mariadb
yum: name=mariadb-server state=latest disable_gpg_check=yes
- name: Initialize DB
shell: mysql_install_db --user=mysql --ldata=/var/lib/mysql/ creates=/var/lib/mysql/mysql
php role
- name: Install remi-release
yum: name=http://rpms.famillecollet.com/enterprise/remi-release-7.rpm state=present disable_gpg_check=yes
- name: Install epel-release
yum: name=epel-release state=latest disable_gpg_check=yes
- name: Install PHP 5.6
yum: name={{ item }} state=latest enablerepo=remi,remi-php56 disable_gpg_check=yes
with_items:
- php-fpm
- php-mbstring
- php-gd
- php-imap
- php-ldap
- php-zip
- php-zlib
- php-mysqlnd
- php-xml
- name: Config php-fpm for user
lineinfile: path=/etc/php-fpm.d/www.conf regexp='^user\s=\sapache$' line='user = nginx'
- name: Config php-fpm for group
lineinfile: path=/etc/php-fpm.d/www.conf regexp='^group\s=\sapache$' line='group = nginx'
- name: Change attribute
file: path='/var/lib/php/{{ item }}' group=nginx
with_items:
- session
- wsdlcache
start role
- files/start.sh 配置
- name: Copy Start script
copy: src=start.sh dest=/root/start.sh mode=755 owner=root group=root
container.yml の作成
version: "2"
settings:
conductor:
base: centos:7
project_name: lime
services:
limesurvey:
from: "centos:7"
roles:
- nginx
- php
- mariadb
- limesurvey
- start
ports:
- "80:80"
command: ["/root/start.sh"]
dev_overrides:
environment:
- "DEBUG=2"
registries: {}
Build & Run
# ansible-container build
Building Docker Engine context...
Starting Docker build of Ansible Container Conductor image (please be patient)...
Parsing conductor CLI args.
Docker? daemon integration engine loaded. Build starting. project=lime
Building service... project=lime service=limesurvey
PLAY [limesurvey] **************************************************************
(略)
PLAY RECAP *********************************************************************
limesurvey : ok=2 changed=1 unreachable=0 failed=0
Applied role to service role=start service=limesurvey
Committed layer as image image=sha256:3bc525a274f0f200f3d6deec0d2c952c1b18b423347b6f3062629ab3c17f595d service=limesurvey
Build complete. service=limesurvey
All images successfully built.
Conductor terminated. Cleaning up. command_rc=0 conductor_id=7e6027e26a72a147c15901f32c68ca9cf94b554ac900c547a367b250fc290461 save_container=False
# # ansible-container run
Parsing conductor CLI args.
Engine integration loaded. Preparing run. engine=Docker? daemon
Verifying service image service=limesurvey
PLAY [Deploy lime] *************************************************************
TASK [docker_service] **********************************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0
All services running. playbook_rc=0
Conductor terminated. Cleaning up. command_rc=0 conductor_id=a47da5e993a652782418978a5538588838501accdaab88690e27bb9b8ccd75a5 save_container=False
# docker ps
WARNING: Error loading config file: /root/.docker/config.json - read /root/.docker/config.json: is a directory
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
87342d1aa3c7 lime-limesurvey:20180227140838 "/root/start.sh" About a minute ago Up About a minute 0.0.0.0:80->80/tcp lime_limesurvey_1
run した後にもう一回 run しても冪等性が保たれる。
# ansible-container run
Parsing conductor CLI args.
Engine integration loaded. Preparing run. engine=Docker? daemon
Verifying service image service=limesurvey
PLAY [Deploy lime] *************************************************************
TASK [docker_service] **********************************************************
ok: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0
All services running. playbook_rc=0
Conductor terminated. Cleaning up. command_rc=0 conductor_id=78904d7a5422cc6e51f5fe9e21bd5120d461178274b97c05032776acada59009 save_container=False
[root@kujira limesurvey]# docker ps -a
WARNING: Error loading config file: /root/.docker/config.json - read /root/.docker/config.json: is a directory
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
87342d1aa3c7 lime-limesurvey:20180227140838 "/root/start.sh" About a minute ago Up About a minute 0.0.0.0:80->80/tcp lime_limesurvey_1
ansible-container の他オプション、stop で停止、restart で再起動、destroyでコンテナの削除
トラブル
ansible-cintainer build 実行時のエラー
ansible-container build fails with AttributeError: 'tuple' object has no attribute 'id'
原因
pip バージョン依存によるエラー
https://github.com/ansible/ansible-container/issues/884
ワークアラウンド
python docker モジュールのダウングレード
# pip show docker
---
Metadata-Version: 2.0
Name: docker
Version: 3.1.0
# pip install -U docker==2.7.0
ansible-container 実行後のワーニング
docker コマンド実行時に毎回出て来る。
# docker ps
WARNING: Error loading config file: /root/.docker/config.json - read /root/.docker/config.json: is a directory
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
原因
解決済み(0.9.3 Fixバージョン)
今回使ってるのは0.9.2なので、アップグレードをまつことにする。
ワークアラウンド
- 無視
- ansible-container build 後に削除 .docker/config.json を削除
3.(おまけ)Migrating from a Dockerfile
ansible-container には Dockerfile からのマイグレーション機能が付いている。
これを使って見たところ下記のような出力と共に YAML ファイルが生成された。
# mkdir migrate_dir
# cd migrate_dir/
# ansible-container import ../dockerfile/limesurvey # ・・・この配下にDockerfileが存在
Project successfully imported. You can find the results in:
/root/migrate_dir
A brief description of what you will find...
container.yml
-------------
The container.yml file is your orchestration file that expresses what services you have and how to build/run them.
settings:
conductor_base: centos:7
services:
limesurvey:
roles:
- limesurvey
I added a single service named limesurvey for your imported Dockerfile.
As you can see, I made an Ansible role for your service, which you can find in:
/root/migrate_dir/roles/limesurvey
migrate_dir/roles/limesurvey/tasks/main.yml
-------------------------------------------
The tasks/main.yml file has your RUN/ADD/COPY instructions.
- name: Ensure /etc/yum.repos.d/ exists
file:
path: /etc/yum.repos.d/
state: directory
- name: Install Nginx (nginx.repo)
copy:
src: nginx.repo
dest: /etc/yum.repos.d/
- shell: yum -y update && yum -y install nginx
- name: Ensure /etc/nginx/conf.d/ exists
file:
path: /etc/nginx/conf.d/
state: directory
- name: Config Nginx for php (default.conf)
copy:
src: default.conf
dest: /etc/nginx/conf.d/
- name: Install PHP 5.6
shell: yum -y install epel-release && yum -y update
- shell: rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
- shell: yum -y install --enablerepo=remi,remi-php56 php-fpm php-mbstring php-gd php-imap
php-ldap php-zip php-zlib php-mysqlnd php-xml
- name: Config php-fpm
shell: sed -i -e "s/^user\s=\sapache$/user = nginx/g" /etc/php-fpm.d/www.conf
- shell: sed -i -e "s/^group\s=\sapache$/group = nginx/g" /etc/php-fpm.d/www.conf
- shell: chgrp -R nginx /var/lib/php/{session,wsdlcache}
- name: Install Mariadb
shell: yum -y install mariadb-server
- name: Config Mariadb
shell: mysql_install_db --user=mysql --ldata=/var/lib/mysql/
- name: Download Limesurvey
shell: mkdir -p /var/www
- shell: curl -L -o /tmp/limesurvey.tar.gz ${URL}
- shell: tar zxf /tmp/limesurvey.tar.gz -C /var/www
- shell: mv /var/www/* /var/www/survey
- shell: chown -R nginx.nginx /var/www/survey
- name: Ensure /root/ exists
file:
path: /root/
state: directory
- name: Set startup (start.sh)
copy:
src: start.sh
dest: /root/
I tried to preserve comments as task names, but you probably want to make
sure each task has a human readable name.
migrate_dir/roles/limesurvey/meta/container.yml
-----------------------------------------------
Metadata from your Dockerfile went into meta/container.yml in your role.
These will be used as build/run defaults for your role.
# Docker file for Lime Survey
from: centos:7
maintainer: Tk
command:
- /root/start.sh
I also stored ARG directives in the role's defaults/main.yml which will used as
variables by Ansible in your build and run operations.
Good luck!
Project imported.
- コメント「#」は -name に置き換わっている
- shell , copy などのモジュール中心に置き換わっている
でもって、できたもので試しにビルドしてみる
# ansible-container build
結果はエラー。
ただ、よく見たら変数指定がおかしくなっているところがあり、そこを直して再実行したら通った。
- shell: curl -L -o /tmp/limesurvey.tar.gz ${URL}
=>
- shell: curl -L -o /tmp/limesurvey.tar.gz {{ URL }}
さっそく、run してみる。
# ansible-container run
Parsing conductor CLI args.
Engine integration loaded. Preparing run. engine=Docker? daemon
Verifying service image service=limesurvey
PLAY [Deploy migrate_dir] ******************************************************
TASK [docker_service] **********************************************************
fatal: [localhost]: FAILED! => {"changed": false, "errors": ["ERROR: for migratedir_limesurvey_1 Cannot start service limesurvey: OCI runtime create failed: container_linux.go:296: starting container process caused \"exec: \\\"/root/start.sh\\\": permission denied\": unknown", "ERROR: for limesurvey Cannot start service limesurvey: OCI runtime create failed: container_linux.go:296: starting container process caused \"exec: \\\"/root/start.sh\\\": permission denied\": unknown"], "failed": true, "module_stderr": "Creating migratedir_limesurvey_1 ... \r\n\r\u001b[1B\nERROR: for migratedir_limesurvey_1 Cannot start service limesurvey: OCI runtime create failed: container_linux.go:296: starting container process caused \"exec: \\\"/root/start.sh\\\": permission denied\": unknown\n\nERROR: for limesurvey Cannot start service limesurvey: OCI runtime create failed: container_linux.go:296: starting container process caused \"exec: \\\"/root/start.sh\\\": permission denied\": unknown\n", "module_stdout": "", "msg": "Error starting project ERROR: for limesurvey Cannot start service limesurvey: OCI runtime create failed: container_linux.go:296: starting container process caused \"exec: \\\"/root/start.sh\\\": permission denied\": unknown"}
to retry, use: --limit @/root/migrate_dir/ansible-deployment/playbook.retry
PLAY RECAP *********************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1
Traceback (most recent call last):
File "/usr/bin/conductor", line 11, in <module>
load_entry_point('ansible-container', 'console_scripts', 'conductor')()
File "/_ansible/container/__init__.py", line 19, in __wrapped__
return fn(*args, **kwargs)
File "/_ansible/container/cli.py", line 399, in conductor_commandline
**params)
File "/_ansible/container/__init__.py", line 19, in __wrapped__
return fn(*args, **kwargs)
File "/_ansible/container/core.py", line 854, in conductorcmd_run
'Error executing the run command. Not all containers may be running.'
container.exceptions.AnsibleContainerException: Error executing the run command. Not all containers may be running.
Conductor terminated. Cleaning up. command_rc=1 conductor_id=467076af06bebe4167568c5fbe21967158517991128d09b4aefce1a0cfdf9902 save_container=False
ERROR Conductor exited with status 1
/root/start.sh の実行属性がとれてしまってるので、下記のようにつけたら run も成功。
# 最後の copy task
- name: Set startup (start.sh)
copy:
src: start.sh
dest: /root/
mode: 0755
ただし、ansible-container run は成功したものの、 Port 部分がアクティブにならなかった。
理由は、Dockerfile に「EXPOSE 80:80」を記載していないため。これをDockerfileに追記し、import することで run も問題なく成功。
なお、この port の設定は下記のファイルに格納されていた。(ansible-container import 実行時の出力にも表示されている)
# Docker file for Lime Survey
from: centos:7
maintainer: Tk
ports:
- 80:80
command:
- /root/start.sh
おまけの、まとめ
ansible-container import のマイグレーションの留意点(version 0.9.2 時点)。
- 変数の確認
- 配布された実行権限付与ファイルの確認
- Dockerfile のパラメータ確認(EXPOSE等)
ansible-container の所感
- まだ1.xになっていないこともあり、若干のBugや留意点が存在
- Dockerfile からのマイグレーションはかなり雑だと思いきや、結構使える(上記、留意点込)
- 他のオーケストレーションへのデプロイも対応しているため、期待できる(今回はそこまでは未確認)