Ansible/Redmineの導入
をテンプレートにして作成
Search in
this wiki
and
or
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
#contents
#br
* Redmineの導入 [#wa722c9e]
Redmineについては、下記3種の導入方法を検討した。
+ 公式サイトの本体コード一式 + RHELのRPM + gemコマンドに...
-- 各々のライブラリ依存性管理が非常に大変。特にnokogiriと...
+ bitnami-redmineを用いた一括導入
-- Git, Redmine, PhpMyAdminなども導入されるが、今回は使わ...
-- Redmine公式ではない
+ 公式dockerイメージを用いた導入
-- dockerを意識して維持管理する手間が生じる
-- ライブラリ間の依存性に悩む必要がなくなる
-- cf. https://qiita.com/bezeklik/items/b9d75ee74e0ae4c6d...
今回は「公式dockerイメージを用いた導入」を採用する。
** 導入サーバの前提条件 [#la5e25ea]
+ OSはRHEL7(or CentOS7)かそれ以降の版とする。
+ 事前導入するソフトウェアパッケージは最小構成。
+ インターネットに接続可能 ※必要ならproxy設定
/etc/dnf/dnf.conf
proxy=http://proxy.jomura.net:8080/ #as your own
~/.bashrc
export HTTP_PROXY=http://proxy.jomura.net:8080/ #as ...
export HTTPS_PROXY=${HTTP_PROXY}
+ パッケージの更新が事前に実行されている
dnf clean all && dnf -y update && reboot
+ Redmine Webサイト用のFully Qualified Domain Name(FQDN)...
** Redmine用 configuration.ymlの作成 [#z6fa156d]
- Ansibleサーバ上の一般ユーザで実行
- SMTP情報は as your own で
cat << "_EOF_" > configuration.yml
default:
email_delivery:
delivery_method: :smtp
smtp_settings:
# tls: true
enable_starttls_auto: true
address: "smtp.gmail.com"
port: 587
domain: "jomura.net"
authentication: :login
user_name: "user@jomura.net"
password: "********"
_EOF_
** Redmine初期設定用SQLの作成 [#t656e6ad]
- Ansibleサーバ上の一般ユーザで実行
cat << "_EOF_" > settings.sql
INSERT INTO `settings` (`name`, `value`) VALUES
('search_results_per_page','30'), -- ページごとの検索結...
('host_name','cxits.tg-group.tokyo-gas.co.jp'), -- ホス...
('protocol','http'), -- プロトコル (http)
('text_formatting','textile'), -- テキスト書式 (textile)
('default_language','ja'), -- デフォルトの言語 (en)
('force_default_language_for_anonymous','0'), -- 匿名ユ...
('force_default_language_for_loggedin','0'), -- ログイ...
('user_format','lastname_firstname'), -- ユーザー名の表...
('thumbnails_enabled','1'), -- 添付ファイルのサムネイル...
('login_required','1'), -- 認証が必要 (0)
('autologin','7'), -- 自動ログイン (0)
('max_additional_emails','3'), -- 追加メールアドレス数...
('session_lifetime','86400'), -- 有効期間の最大値 (0)
('session_timeout','240'), -- 無操作タイムアウト (0)
('default_users_time_zone','Tokyo'), -- タイムゾーン ()
('rest_api_enabled','1'), -- RESTによるWebサービスを有...
('jsonp_enabled','1'), -- JSONPを有効にする (0)
('default_projects_public','0'), -- デフォルトで新しい...
('default_projects_modules','---
- issue_tracking
- time_tracking
- wiki
- repository
- calendar
- gantt
'), -- 新規プロジェクトにおいてデフォルトで有効になるモ...
('default_projects_tracker_ids','---
- \'1\'
- \'2\'
- \'3\'
'), -- 新規プロジェクトにおいてデフォルトで有効になるト...
('cross_project_issue_relations','1'), -- 異なるプロジ...
('default_issue_start_date_to_creation_date','1'), -- ...
('issue_done_ratio','issue_status'), -- 進捗率の算出方...
('issue_list_default_totals','---
- estimated_hours
- spent_hours
'), -- チケットの一覧で表示する項目(合計)
('attachment_max_size','51200'), -- 添付ファイルサイズ...
('repositories_encodings','utf-8,cp932,euc-jp'), -- 添...
('mail_from','user@jomura.net'), -- 送信元メールアドレ...
('enabled_scm','---
- Subversion
- Git
'), -- 使用するバージョン管理システム
('commit_ref_keywords','refs,references,IssueID,*'), --...
('commit_cross_project_ref','1'); -- 異なるプロジェクト...
_EOF_
** docker-compose.ymlファイルの作成 [#z4d0976f]
- Ansibleサーバ上の一般ユーザで実行
cat << "_EOF_" > docker-compose.yml
version: '3.7'
services:
redmine:
container_name: ${REDMINE:-redmine}
image: redmine:4-passenger
restart: always
ports:
- 3000:3000
depends_on:
- ${REDMINE_DB_MYSQL:-mysql}
- ${REDMINE_MEMCACHED:-memcached}
environment:
TZ: ${TZ}
REDMINE_DB_MYSQL: ${REDMINE_DB_MYSQL:-mysql}
REDMINE_DB_DATABASE: ${REDMINE_DB_DATABASE}
REDMINE_DB_USERNAME: ${REDMINE_DB_USERNAME}
REDMINE_DB_PASSWORD: ${REDMINE_DB_PASSWORD}
REDMINE_DB_ENCODING: ${REDMINE_DB_ENCODING:-utf8m...
{% if proxy_env.http_proxy is defined %}
HTTP_PROXY: {{ proxy_env.http_proxy }}
HTTPS_PROXY: {{ proxy_env.https_proxy }}
{% endif %}
volumes:
- ${REDMINE_PATH:-.}/config/additional_environmen...
- ${REDMINE_PATH:-.}/config/configuration.yml:/us...
- ${REDMINE_PATH:-.}/Gemfile.local:/usr/src/redmi...
- ${REDMINE_PATH:-.}/files:/usr/src/redmine/files:z
- ${REDMINE_PATH:-.}/log:/usr/src/redmine/log:Z
- ${REDMINE_PATH:-.}/plugins:/usr/src/redmine/plu...
- ${REDMINE_PATH:-.}/public/themes:/usr/src/redmi...
- /var/lib/svn:/var/lib/svn:z
- /var/lib/git:/var/lib/git:z
mysql:
container_name: ${REDMINE_DB_MYSQL:-mysql}
image: mysql:8
command: --default-authentication-plugin=mysql_nati...
restart: always
ports:
- 3306:3306
environment:
TZ: ${TZ}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${REDMINE_DB_DATABASE}
MYSQL_USER: ${REDMINE_DB_USERNAME}
MYSQL_PASSWORD: ${REDMINE_DB_PASSWORD}
volumes:
- mysql-data:/var/lib/mysql
- ${REDMINE_PATH:-.}/../mysql/conf.d/redmine.cnf:...
memcached:
container_name: ${REDMINE_MEMCACHED:-memcached}
image: memcached
restart: always
volumes:
mysql-data:
name: mysql-data
_EOF_
** docker用環境変数ファイルの作成 [#mef56985]
- Ansibleサーバ上の一般ユーザで実行
cat << _EOF_ > docker-env
REDMINE_PATH={{ redmine_path }}
TZ=Asia/Tokyo
MYSQL_ROOT_PASSWORD=$(< /dev/urandom tr -dc 'A-Za-z0-9!$...
REDMINE_DB_MYSQL=mysql
REDMINE_DB_DATABASE=redmine
REDMINE_DB_USERNAME=redmine
REDMINE_DB_PASSWORD=$(< /dev/urandom tr -dc 'A-Za-z0-9!$...
REDMINE_DB_ENCODING=utf8mb4
REDMINE_MEMCACHED=memcached
_EOF_
chmod go-rwx docker-env
- catに指定する _EOF_ を"でくくってはいけない。urandamコ...
** playbookの作成 [#y22e4e40]
- Ansibleサーバ上の一般ユーザで実行
- sudoの場合、become_method: sudo
cat << "_EOF_" > pb_redmine_server-redmine.yml
# install redmine
- hosts: redmine_servers
become: true
become_method: su
environment: "{{ proxy_env }}"
vars:
redmine_path: /srv/redmine
tasks:
- name: check facts
fail:
msg: "Not compatible with [{{ ansible_os_family ...
{{ ansible_distribution }} \
{{ ansible_distribution_major_version }}."
when: >
ansible_os_family != 'RedHat'
or ansible_distribution_major_version|int < 7
- name: add docker repo
shell: dnf config-manager --add-repo https://downl...
args:
warn: false
changed_when: false
- name: install RPMs
dnf:
name:
- httpd
- docker-ce
state: latest
- name: set proxy for docker
file: path=/etc/systemd/system/docker.service.d st...
when: proxy_env.http_proxy is defined
- copy:
dest: /etc/systemd/system/docker.service.d/http-...
force: no
content: "[Service]\n \
Environment = \"http_proxy={{ proxy_env.http_p...
\"https_proxy={{ proxy_env.https_proxy }}\"\n"
when: proxy_env.http_proxy is defined
- name: restart Docker
systemd:
name: docker
state: restarted
daemon_reload: yes
enabled: yes
- name: install docker-compose
stat: path=/usr/local/bin/docker-compose
register: result01
- shell: |
curl --location --output /usr/local/bin/docker-c...
$(curl --silent --show-error \
https://api.github.com/repos/docker/compose/...
| grep 'Linux-x86_64"' \
| grep url \
| cut --delimiter='"' --fields=4 \
)
chmod +x /usr/local/bin/docker-compose
args:
warn: false
when: result01.stat.exists == false
- name: "create {{ redmine_path }}"
file: path={{ redmine_path }} state=directory
register: result02
- shell: |
/usr/sbin/matchpathcon {{ redmine_path }}
/usr/sbin/semanage fcontext --add --type contain...
/usr/sbin/restorecon -v {{ redmine_path }}
/usr/sbin/matchpathcon {{ redmine_path }}
args:
warn: false
when: result02.changed == true
- name: create config files
file: path={{ redmine_path }}/config state=directory
- copy:
src: configuration.yml
dest: "{{ redmine_path }}/config/configuration.y...
force: no
- copy:
dest: "{{ redmine_path }}/config/additional_envi...
force: no
content: |
config.cache_store = :mem_cache_store, "memcac...
config.logger = Logger.new("#{Rails.root}/log/...
config.logger.level = Logger::INFO
- copy:
dest: "{{ redmine_path }}/Gemfile.local"
force: no
content: "gem 'dalli'\n "
- file: path={{ redmine_path }}/../mysql/conf.d stat...
- copy:
dest: "{{ redmine_path }}/../mysql/conf.d/redmin...
force: no
content: |
[mysqld]
innodb_buffer_pool_size = 536870912
innodb_log_file_size = 201326592
- name: create a parent dir of svn-repos
file:
path: /var/lib/svn
owner: nobody
group: users
state: directory
mode: 02775
register: result03
- shell: |
/usr/sbin/semanage fcontext -a -t git_rw_content...
/usr/sbin/restorecon -Rv /var/lib/svn
args:
warn: false
when: result03.changed == true
- name: create a parent dir of git-repos
file:
path: /var/lib/git
owner: nobody
group: users
state: directory
mode: 02775
register: result03
- shell: |
/usr/sbin/semanage fcontext -a -t git_rw_content...
/usr/sbin/restorecon -Rv /var/lib/git
args:
warn: false
when: result03.changed == true
- name: docker-compose up
template:
src: docker-compose.yml
dest: "{{ redmine_path }}/docker-compose.yml"
force: no
- template:
src: docker-env
dest: "{{ redmine_path }}/.env"
force: no
mode: 0400
- shell: docker-compose --project-directory {{ redmi...
args:
chdir: "{{ redmine_path }}"
register: result04
changed_when: '" is up-to-date" not in result04.st...
- name: wait for Completed 200 OK
shell: docker container logs redmine 2>/dev/null |...
register: result05
changed_when: false
until: '"Completed 200 OK " in result05.stdout'
retries: 100
delay: 5
- name: set db password file
slurp:
src: "{{ redmine_path }}/.env"
register: result06
- copy:
dest: ~/.my.cnf.org
force: no
mode: 0400
content: "[client]\nuser = redmine\n \
password = {{ result06['content'] | b64decode ...
regex_findall('REDMINE_DB_PASSWORD=(.+)\\n') |...
host = localhost\n"
register: result07
- shell: docker cp ~/.my.cnf.org mysql:root/.my.cnf
when: result07.changed
- name: load default data
shell: docker exec {% if proxy_env.http_proxy is d...
-e HTTP_PROXY={{ proxy_env.http_proxy }} -e HTTP...
redmine bundle exec rake redmine:load_default_da...
register: result08
changed_when: '" is already loaded." not in result...
- name: update roles
shell: |
cat << '_EOQ_' | docker exec -i mysql mysql redm...
UPDATE `roles` SET `permissions` = NULL WHERE `i...
_EOQ_
changed_when: false
- name: insert settings
shell: |
cat << '_EOQ_' | docker exec -i mysql mysql redm...
SELECT count(*) FROM `settings`
_EOQ_
changed_when: false
register: result09
- shell: |
cat settings.sql | docker exec --interactive mys...
docker exec redmine passenger-config restart-app...
when: result09.stdout_lines[1] == "0"
- name: clear rails cache
shell: docker exec {% if proxy_env.http_proxy is d...
-e HTTP_PROXY={{ proxy_env.http_proxy }} -e HTTP...
redmine bundle exec rails runner 'Rails.cache.cl...
changed_when: false
- name: bundle install
shell: docker exec {% if proxy_env.http_proxy is d...
-e HTTP_PROXY={{ proxy_env.http_proxy }} -e HTTP...
redmine bundle install
changed_when: false
- name: restart passenger
shell: docker exec {% if proxy_env.http_proxy is d...
-e HTTP_PROXY={{ proxy_env.http_proxy }} -e HTTP...
redmine passenger-config restart-app /usr/src/re...
changed_when: false
- name: modify httpd.conf for redmine
copy:
dest: /etc/httpd/conf.d/proxy-redmine.conf
force: no
mode: 0644
content: |
<IfModule !proxy_module>
LoadModule proxy_module modules/mod_proxy.so
</IfModule>
<IfModule !proxy_http_module>
LoadModule proxy_http_module modules/mod_pro...
</IfModule>
ProxyPassMatch /git.* !
ProxyPassMatch /svn.* !
ProxyPassMatch /kibana.* !
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
- name: httpd_can_network_connect
shell: /usr/sbin/getsebool httpd_can_network_connect
register: result10
- shell: /usr/sbin/setsebool -P httpd_can_network_co...
when: result10.stdout == 'httpd_can_network_connec...
notify:
- restart Apache
- name: open ports
firewalld:
service: "{{ item }}"
permanent: true
state: enabled
immediate: yes
loop:
- http
- https
- file: path={{ redmine_path }}/../backup state=dire...
- name: backup-redmine-db.service
copy:
dest: /etc/systemd/system/backup-redmine-db.serv...
content: |
[Unit]
Description=backup redmine db
[Service]
Type=oneshot
ExecStart=/bin/sh -c "docker exec mysql mysqld...
| gzip > {{ redmine_path }}/../backup/redmin...
ExecStartPost=/bin/find {{ redmine_path }}/../...
-name "redmine_db_*.sql.gz" -mtime +30 -delete
- name: backup-redmine-db.timer
copy:
dest: /etc/systemd/system/backup-redmine-db.timer
content: |
[Unit]
Description=backup redmine db
[Timer]
OnCalendar=daily
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
- name: backup-redmine-files.service
copy:
dest: /etc/systemd/system/backup-redmine-files.s...
content: |
[Unit]
Description=backup redmine files
[Service]
Type=oneshot
ExecStart=/bin/sh -c "tar -C {{ redmine_path }...
-czf {{ redmine_path }}/../backup/redmine_fi...
files"
ExecStartPost=/bin/find {{ redmine_path }}/../...
-name "redmine_files_*.tar.gz" -mtime +30 -d...
- name: backup-redmine-files.timer
copy:
dest: /etc/systemd/system/backup-redmine-files.t...
content: |
[Unit]
Description=backup redmine files
[Timer]
OnCalendar=daily
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
- name: enable timers
systemd:
name: "{{ item }}"
daemon_reload: yes
enabled: yes
state: started
loop:
- backup-redmine-db.timer
- backup-redmine-files.timer
- name: check
shell: systemctl list-unit-files | egrep "STATE|ba...
changed_when: false
register: result01
- debug: msg="{{ result01.stdout_lines }}"
handlers:
- name: restart Apache
systemd:
name: httpd
state: restarted
daemon_reload: yes
enabled: yes
_EOF_
- docker_composeはRPMパッケージではなく最新版を使う
** playbookの実行 [#x17c57c6]
- Ansibleサーバ上の一般ユーザで実行
- 実行前に文法チェックしよう
ansible-playbook -i inventory.yml pb_redmine_server-redm...
- 問題なければ実効
ansible-playbook -i inventory.yml pb_redmine_server-redm...
** 補足事項 [#nccd8e9f]
+ mysqlコンテナを削除すると、DBデータはどうなる?
ホストの /var/lib/docker/volumes/mysql/_data/ にMySQLの...
+ mysql_native_passwordの指定は必要?
defaultのsha2_passwordにrailsが対応していない場合を考慮...
+ MySQLやmemcashedは、コンテナではなく、ホスト側にrpm導入...
dockerコンテナからホストのプロセスに通信するには、便利...
同一のcompose.ymlファイルに記述されたコンテナは、同一ネ...
+ RedmineのURLに、コンテキストパス(/redmine)を設定できる?
RedmineのWebサイトに紹介されている。dockerコンテナ内のp...
今回は、「基本的に全てのURL要求をredmineコンテナにproxy...
+ MySQLへの設定追加
ホストの/srv/mysql/conf.d/redmine.cnf に永続化されてい...
ファイルに記述する前に、"set global …"コマンドを用いて...
また、slow queryの常時出力設定は不要と考えている。必要...
set global slow_query_log_file = 'slow.log';
set global long_query_time = 5;
set global slow_query_log = ON;
+ Redmine導入用のplaybookに、git用のタスクがあるんだけど
gitリポジトリ用のSELinux設定は、Redmine用のdocker-compo...
+ ログの循環
Apache HTTP Serverのaccess_log, error_logは、logrotated...
Redmineのproduction.logは、additional_environment.rbで...
* Pluginの導入 [#y8a09536]
** playbookの作成 [#p6694df9]
- Ansibleサーバ上の一般ユーザで実行する。
cat << "_EOF_" > pb_redmine_server-plugin.yml
# install redmine plugins
# dependencies: pb_redmine_server-redmine.yml
- hosts: redmine_servers
become: true
become_method: su
environment: "{{ proxy_env }}"
vars:
redmine_path: /srv/redmine
tasks:
- name: check facts
fail:
msg: "Not compatible with [{{ ansible_os_family ...
{{ ansible_distribution }} \
{{ ansible_distribution_major_version }}."
when: >
ansible_os_family != 'RedHat'
or ansible_distribution_major_version|int < 7
- name: check redmine
stat: path={{ redmine_path }}
register: result01
- fail:
msg: "pb_redmine_server.yml has been executed ye...
when: result01.stat.exists == false
- name: install RPMs
dnf:
name:
- git
state: latest
- name: redmine_pivot_table
shell: >
git clone --depth 1
https://github.com/deecay/redmine_pivot_table
./plugins/redmine_pivot_table
args:
chdir: "{{ redmine_path }}"
notify:
- restart Redmine
handlers:
- name: restart Redmine
shell: |
docker exec redmine bundle exec rake redmine:plu...
docker exec redmine passenger-config restart-app...
_EOF_
** playbookの実行 [#d1fba2df]
- Ansibleサーバ上の一般ユーザで実行
ansible-playbook -i inventory.yml pb_redmine_server-plug...
* Gitの導入 [#af224b39]
GitLabは「Redmineとの連携は結構面倒」なのと「リソース(...
** Apache用設定ファイルの作成 [#f8c6ab05]
- Ansibleサーバ上の一般ユーザで実行
cat << "_EOF_" > repos-git.conf
#<IfModule mod_rewrite.c>
# RewriteEngine On
# RewriteCond %{REQUEST_URI} ^/git/?$
# RewriteRule ^/git /gitweb [R=301,L]
## RewriteRule ^/git/$ /gitweb/ [L,R]
#</IfModule>
PerlLoadModule Apache::Authn::Redmine
SetEnv GIT_PROJECT_ROOT /var/lib/git
SetEnv GIT_HTTP_EXPORT_ALL
ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/
<Location /git/>
Order allow,deny
Allow from all
PerlAccessHandler Apache::Authn::Redmine::access_handler
PerlAuthenHandler Apache::Authn::Redmine::authen_handler
AuthType Basic
AuthName Git
# <LimitExcept GET PROPFIND OPTIONS REPORT>
# SSLRequireSSL
# </LimitExcept>
# for Redmine Authentication
RedmineDSN "DBI:mysql:database=redmine;host=127.0.0.1"
RedmineDbUser "redmine"
RedmineDbPass ""
RedmineGitSmartHttp yes
Require valid-user
# SetEnvIf Request_URI "^/git/$" allow
# Order allow,deny
# Allow from env=allow
# Satisfy any
</Location>
_EOF_
- contextpath"/git"ではなく、VirtualHostにしてもいい。
** playbookの作成 [#t40d7aae]
- Ansibleサーバ上の一般ユーザで実行
- sudoの場合、become_method: sudo
cat << "_EOF_" > pb_redmine_server-git.yml
# install git
# dependencies: pb_redmine_server-redmine.yml
- hosts: redmine_servers
become: true
become_method: su
environment: "{{ proxy_env }}"
vars:
redmine_path: /srv/redmine
tasks:
- name: check facts
fail:
msg: "Not compatible with [{{ ansible_os_family ...
{{ ansible_distribution }} \
{{ ansible_distribution_major_version }}."
when: >
ansible_os_family != 'RedHat'
or ansible_distribution_major_version|int < 7
- name: check redmine
stat: path={{ redmine_path }}
register: result01
- fail:
msg: "pb_redmine_server.yml has been executed ye...
when: result01.stat.exists == false
- name: install RPMs
dnf:
name:
- httpd
- git
- mod_perl
- perl-Digest-SHA
- perl-DBI
- perl-DBD-mysql
# - gitweb
state: latest
- name: modify apache user for git
user: name=apache groups=users append=yes
notify:
- restart Apache
- name: set env for git
file: path=/etc/systemd/system/httpd.service.d sta...
- copy:
dest: /etc/systemd/system/httpd.service.d/git.conf
force: no
content: "[Service]\nUMask=002\n"
notify:
- restart Apache
- name: copy Redmine.pm
file: path=/etc/httpd/Apache/Authn state=directory
- shell: docker cp redmine:/usr/src/redmine/extra/sv...
- name: create repos-git.conf
copy:
src: repos-git.conf
dest: /etc/httpd/conf.d/repos-git.conf
force: no
mode: 0640
- slurp:
src: "{{ redmine_path }}/.env"
register: result03
- lineinfile:
dest: /etc/httpd/conf.d/repos-git.conf
regexp: "^ RedmineDbPass"
line: " RedmineDbPass {{ result03['content'] | ...
| regex_findall('REDMINE_DB_PASSWORD=(.+)\\n')...
notify:
- restart Apache
# - name: modify gitweb
# lineinfile:
# dest: /etc/httpd/conf.d/git.conf
# regexp: '^Alias /git /var/www/git$'
# line: 'Alias /gitweb /var/www/git'
- file: path={{ redmine_path }}/../backup state=dire...
- name: backup-git-repos.service
copy:
dest: /etc/systemd/system/backup-git-repos.service
content: |
[Unit]
Description=backup git repositories
[Service]
Type=oneshot
ExecStart=/bin/sh -c "tar -C /var/lib/git \
-czf {{ redmine_path }}/../backup/git_repos_...
."
ExecStartPost=/bin/find {{ redmine_path }}/../...
-name "git_repos_*.tar.gz" -mtime +30 -delete
- name: backup-git-repos.timer
copy:
dest: /etc/systemd/system/backup-git-repos.timer
content: |
[Unit]
Description=backup git repositories
[Timer]
OnCalendar=daily
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
- name: enable timers
systemd:
name: "{{ item }}"
daemon_reload: yes
enabled: yes
state: started
loop:
- backup-git-repos.timer
- name: check
shell: systemctl list-unit-files | egrep "STATE|ba...
changed_when: false
register: result01
- debug: msg="{{ result01.stdout_lines }}"
handlers:
- name: restart Apache
systemd:
name: httpd
state: restarted
daemon_reload: yes
enabled: yes
_EOF_
** playbookの実行 [#ie6760c5]
- Ansibleサーバ上の一般ユーザで実行
ansible-playbook -i inventory.yml pb_redmine_server-git....
* Subversionの導入 [#x030af9c]
Git嫌な人のために、Subversionも入れちゃう。
** Apache用設定ファイルの作成 [#t0ca81c9]
- Ansibleサーバ上の一般ユーザで実行
cat << "_EOF_" > repos-svn.conf
LimitRequestFieldSize 12392
LoadModule perl_module modules/mod_perl.so
PerlLoadModule Apache::Authn::Redmine
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
RequestHeader edit Destination ^https http early
<Location /svn>
LimitXMLRequestBody 0
DAV svn
SVNParentPath /var/lib/svn
SVNListParentPath on
# SVNIndexXSLT "/svnindex/svnindex.xsl"
# SVNPathAuthz off
# http://www.redmine.org/boards/2/topics/7593
AuthType Basic
AuthName Subversion
PerlAccessHandler Apache::Authn::Redmine::access_handler
PerlAuthenHandler Apache::Authn::Redmine::authen_handler
RedmineDSN "DBI:mysql:database=redmine;host=127.0.0.1"
RedmineDbUser "redmine"
RedmineDbPass ""
## Optional where clause (fulltext search would be slo...
## database dependant).
# RedmineDbWhereClause "and exists (select * from group...
#where users.id = groups_users.user_id and groups_users....
#= (select id from users where type = 'Group' and lastname
#= 'committers'));"
## Optional credentials cache size
# RedmineCacheCredsMax 50
SetEnvIf REQUEST_URI "^/svn/?$" parent
<RequireAny>
Require env parent
Require valid-user
</RequireAny>
</Location>
_EOF_
- contextpath"/svn"ではなく、VirtualHostにしてもいい。
** playbookの作成 [#x639382d]
- Ansibleサーバ上の一般ユーザで実行
- sudoの場合、become_method: sudo
cat << "_EOF_" > pb_redmine_server-svn.yml
# install svn
# dependencies: pb_redmine_server-redmine.yml
- hosts: redmine_servers
become: true
become_method: su
environment: "{{ proxy_env }}"
vars:
redmine_path: /srv/redmine
tasks:
- name: check facts
fail:
msg: "Not compatible with [{{ ansible_os_family ...
{{ ansible_distribution }} \
{{ ansible_distribution_major_version }}."
when: >
ansible_os_family != 'RedHat'
or ansible_distribution_major_version|int < 7
- name: check redmine
stat: path={{ redmine_path }}
register: result01
- fail:
msg: "pb_redmine_server.yml has been executed ye...
when: result01.stat.exists == false
- name: install RPMs
dnf:
name:
- httpd
- subversion
- mod_dav_svn
- mod_perl
- perl-Digest-SHA
- perl-DBI
- perl-DBD-mysql
state: latest
- name: modify apache user for svn
user: name=apache groups=users append=yes
notify:
- restart Apache
- name: set env for svn
file: path=/etc/systemd/system/httpd.service.d sta...
- copy:
dest: /etc/systemd/system/httpd.service.d/svn.conf
force: no
content: "[Service]\nEnvironment=LANG='ja_JP.UTF...
notify:
- restart Apache
- name: copy Redmine.pm
file: path=/etc/httpd/Apache/Authn state=directory
- shell: docker cp redmine:/usr/src/redmine/extra/sv...
- name: create repos-svn.conf
copy:
src: repos-svn.conf
dest: /etc/httpd/conf.d/repos-svn.conf
force: no
mode: 0640
- slurp:
src: "{{ redmine_path }}/.env"
register: result03
- lineinfile:
dest: /etc/httpd/conf.d/repos-svn.conf
regexp: "^ RedmineDbPass"
line: " RedmineDbPass {{ result03['content'] | ...
| regex_findall('REDMINE_DB_PASSWORD=(.+)\\n')...
notify:
- restart Apache
- file: path={{ redmine_path }}/../backup state=dire...
- name: backup-svn-repos.service
copy:
dest: /etc/systemd/system/backup-svn-repos.service
content: |
[Unit]
Description=backup svn repositories
[Service]
Type=oneshot
ExecStart=/bin/sh -c "tar -C /var/lib/svn \
-czf {{ redmine_path }}/../backup/svn_repos_...
."
ExecStartPost=/bin/find {{ redmine_path }}/../...
-name "svn_repos_*.tar.gz" -mtime +30 -delete
- name: backup-svn-repos.timer
copy:
dest: /etc/systemd/system/backup-svn-repos.timer
content: |
[Unit]
Description=backup svn repositories
[Timer]
OnCalendar=daily
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
- name: enable timers
systemd:
name: "{{ item }}"
daemon_reload: yes
enabled: yes
state: started
loop:
- backup-svn-repos.timer
- name: check
shell: systemctl list-unit-files | egrep "STATE|ba...
changed_when: false
register: result01
- debug: msg="{{ result01.stdout_lines }}"
handlers:
- name: restart Apache
systemd:
name: httpd
state: restarted
daemon_reload: yes
enabled: yes
_EOF_
** playbookの実行 [#afa695a9]
- Ansibleサーバ上の一般ユーザで実行
ansible-playbook -i inventory.yml pb_redmine_server-svn....
* 管理作業 [#bed50813]
** Gitリポジトリの新規作成 [#x46884bc]
- Ansibleで実施すると簡便か?
- Ansibleサーバ上の一般ユーザで実行。対象サーバの実行アカ...
cat << "_EOF_" > pb_create_git_repository.yml
# create git repository
- hosts: all
vars:
gitrepos_path: /var/lib/git
ansible_user: user #as your own
ansible_password: user #as your own
vars_prompt:
- name: repos_name
prompt: "Enter the reposotory name. "
default: myrepos.git
private: no
tasks:
- debug:
msg: "The repos_name is {{ repos_name }}."
- fail: msg="The string you enter is not a valid rep...
when: repos_name is not regex("[a-z].+\..+")
- stat: path="{{ gitrepos_path }}/{{ repos_name }}"
register: result00
- fail: msg="Already exists."
when: result00.stat.exists == true
- shell: groups
register: result01
- debug:
msg: "Your groups is {{ result01.stdout.split(' ...
- fail: msg="You do not have permission to create a ...
when: "'users' not in result01.stdout.split(' ')"
- shell: "git init --bare --shared {{ gitrepos_path ...
- shell: >
git update-server-info
&& cp hooks/post-update.sample hooks/post-update
&& git config --local core.ignorecase false
&& git config --local core.quotepath false
args:
chdir: "{{ gitrepos_path }}/{{ repos_name }}/"
# - copy:
# dest: "{{ gitrepos_path }}/{{ repos_name }}/clo...
# content: "<a href=\"http://{{ inventory_hostnam...
# >http://{{ inventory_hostname }}/git/{{ repos...
# - copy:
# dest: "{{ gitrepos_path }}/{{ repos_name }}/des...
# content: "((TODO: descriptionファイルへ、リポジ...
# - copy:
# dest: "{{ gitrepos_path }}/{{ repos_name }}/REA...
# content: "<h3>概要</h3>\n \
# ((TODO: ここにはリポジトリの説明を書...
# <h3>ルール・留意点</h3>\n \
# ((TODO: ここにはリポジトリ利用に際し...
# <h3>問い合わせ先・管理者</h3>\n \
# ((TODO: ここにはリポジトリに対しての...
# <hr />\n \
# ※TODO: このテンプレートにこだわらず、...
_EOF_
- Ansibleサーバ上の一般ユーザで実行
ansible-playbook -i its.jomura.net, pb_create_git_reposi...
-- リポジトリ名を問われるので、入力する
Enter the repository name. [myrepos.git]:
- または、"-e"オプションでリポジトリ名を指定することもで...
ansible-playbook -i its.jomura.net, -e repos_name=myrepo...
- リポジトリ名の"."より前は、Redmineプロジェクトの"識別子...
- /var/lib/git/{リポジトリ名}/ の直下に、下記のファイルを...
++ README.html : リポジトリの説明をHTMLで記述する。
++ description : リポジトリの説明を簡単に1行程度で記述す...
++ cloneurl : リポジトリアクセス用のURLを記述する。有用。
終了行:
#contents
#br
* Redmineの導入 [#wa722c9e]
Redmineについては、下記3種の導入方法を検討した。
+ 公式サイトの本体コード一式 + RHELのRPM + gemコマンドに...
-- 各々のライブラリ依存性管理が非常に大変。特にnokogiriと...
+ bitnami-redmineを用いた一括導入
-- Git, Redmine, PhpMyAdminなども導入されるが、今回は使わ...
-- Redmine公式ではない
+ 公式dockerイメージを用いた導入
-- dockerを意識して維持管理する手間が生じる
-- ライブラリ間の依存性に悩む必要がなくなる
-- cf. https://qiita.com/bezeklik/items/b9d75ee74e0ae4c6d...
今回は「公式dockerイメージを用いた導入」を採用する。
** 導入サーバの前提条件 [#la5e25ea]
+ OSはRHEL7(or CentOS7)かそれ以降の版とする。
+ 事前導入するソフトウェアパッケージは最小構成。
+ インターネットに接続可能 ※必要ならproxy設定
/etc/dnf/dnf.conf
proxy=http://proxy.jomura.net:8080/ #as your own
~/.bashrc
export HTTP_PROXY=http://proxy.jomura.net:8080/ #as ...
export HTTPS_PROXY=${HTTP_PROXY}
+ パッケージの更新が事前に実行されている
dnf clean all && dnf -y update && reboot
+ Redmine Webサイト用のFully Qualified Domain Name(FQDN)...
** Redmine用 configuration.ymlの作成 [#z6fa156d]
- Ansibleサーバ上の一般ユーザで実行
- SMTP情報は as your own で
cat << "_EOF_" > configuration.yml
default:
email_delivery:
delivery_method: :smtp
smtp_settings:
# tls: true
enable_starttls_auto: true
address: "smtp.gmail.com"
port: 587
domain: "jomura.net"
authentication: :login
user_name: "user@jomura.net"
password: "********"
_EOF_
** Redmine初期設定用SQLの作成 [#t656e6ad]
- Ansibleサーバ上の一般ユーザで実行
cat << "_EOF_" > settings.sql
INSERT INTO `settings` (`name`, `value`) VALUES
('search_results_per_page','30'), -- ページごとの検索結...
('host_name','cxits.tg-group.tokyo-gas.co.jp'), -- ホス...
('protocol','http'), -- プロトコル (http)
('text_formatting','textile'), -- テキスト書式 (textile)
('default_language','ja'), -- デフォルトの言語 (en)
('force_default_language_for_anonymous','0'), -- 匿名ユ...
('force_default_language_for_loggedin','0'), -- ログイ...
('user_format','lastname_firstname'), -- ユーザー名の表...
('thumbnails_enabled','1'), -- 添付ファイルのサムネイル...
('login_required','1'), -- 認証が必要 (0)
('autologin','7'), -- 自動ログイン (0)
('max_additional_emails','3'), -- 追加メールアドレス数...
('session_lifetime','86400'), -- 有効期間の最大値 (0)
('session_timeout','240'), -- 無操作タイムアウト (0)
('default_users_time_zone','Tokyo'), -- タイムゾーン ()
('rest_api_enabled','1'), -- RESTによるWebサービスを有...
('jsonp_enabled','1'), -- JSONPを有効にする (0)
('default_projects_public','0'), -- デフォルトで新しい...
('default_projects_modules','---
- issue_tracking
- time_tracking
- wiki
- repository
- calendar
- gantt
'), -- 新規プロジェクトにおいてデフォルトで有効になるモ...
('default_projects_tracker_ids','---
- \'1\'
- \'2\'
- \'3\'
'), -- 新規プロジェクトにおいてデフォルトで有効になるト...
('cross_project_issue_relations','1'), -- 異なるプロジ...
('default_issue_start_date_to_creation_date','1'), -- ...
('issue_done_ratio','issue_status'), -- 進捗率の算出方...
('issue_list_default_totals','---
- estimated_hours
- spent_hours
'), -- チケットの一覧で表示する項目(合計)
('attachment_max_size','51200'), -- 添付ファイルサイズ...
('repositories_encodings','utf-8,cp932,euc-jp'), -- 添...
('mail_from','user@jomura.net'), -- 送信元メールアドレ...
('enabled_scm','---
- Subversion
- Git
'), -- 使用するバージョン管理システム
('commit_ref_keywords','refs,references,IssueID,*'), --...
('commit_cross_project_ref','1'); -- 異なるプロジェクト...
_EOF_
** docker-compose.ymlファイルの作成 [#z4d0976f]
- Ansibleサーバ上の一般ユーザで実行
cat << "_EOF_" > docker-compose.yml
version: '3.7'
services:
redmine:
container_name: ${REDMINE:-redmine}
image: redmine:4-passenger
restart: always
ports:
- 3000:3000
depends_on:
- ${REDMINE_DB_MYSQL:-mysql}
- ${REDMINE_MEMCACHED:-memcached}
environment:
TZ: ${TZ}
REDMINE_DB_MYSQL: ${REDMINE_DB_MYSQL:-mysql}
REDMINE_DB_DATABASE: ${REDMINE_DB_DATABASE}
REDMINE_DB_USERNAME: ${REDMINE_DB_USERNAME}
REDMINE_DB_PASSWORD: ${REDMINE_DB_PASSWORD}
REDMINE_DB_ENCODING: ${REDMINE_DB_ENCODING:-utf8m...
{% if proxy_env.http_proxy is defined %}
HTTP_PROXY: {{ proxy_env.http_proxy }}
HTTPS_PROXY: {{ proxy_env.https_proxy }}
{% endif %}
volumes:
- ${REDMINE_PATH:-.}/config/additional_environmen...
- ${REDMINE_PATH:-.}/config/configuration.yml:/us...
- ${REDMINE_PATH:-.}/Gemfile.local:/usr/src/redmi...
- ${REDMINE_PATH:-.}/files:/usr/src/redmine/files:z
- ${REDMINE_PATH:-.}/log:/usr/src/redmine/log:Z
- ${REDMINE_PATH:-.}/plugins:/usr/src/redmine/plu...
- ${REDMINE_PATH:-.}/public/themes:/usr/src/redmi...
- /var/lib/svn:/var/lib/svn:z
- /var/lib/git:/var/lib/git:z
mysql:
container_name: ${REDMINE_DB_MYSQL:-mysql}
image: mysql:8
command: --default-authentication-plugin=mysql_nati...
restart: always
ports:
- 3306:3306
environment:
TZ: ${TZ}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${REDMINE_DB_DATABASE}
MYSQL_USER: ${REDMINE_DB_USERNAME}
MYSQL_PASSWORD: ${REDMINE_DB_PASSWORD}
volumes:
- mysql-data:/var/lib/mysql
- ${REDMINE_PATH:-.}/../mysql/conf.d/redmine.cnf:...
memcached:
container_name: ${REDMINE_MEMCACHED:-memcached}
image: memcached
restart: always
volumes:
mysql-data:
name: mysql-data
_EOF_
** docker用環境変数ファイルの作成 [#mef56985]
- Ansibleサーバ上の一般ユーザで実行
cat << _EOF_ > docker-env
REDMINE_PATH={{ redmine_path }}
TZ=Asia/Tokyo
MYSQL_ROOT_PASSWORD=$(< /dev/urandom tr -dc 'A-Za-z0-9!$...
REDMINE_DB_MYSQL=mysql
REDMINE_DB_DATABASE=redmine
REDMINE_DB_USERNAME=redmine
REDMINE_DB_PASSWORD=$(< /dev/urandom tr -dc 'A-Za-z0-9!$...
REDMINE_DB_ENCODING=utf8mb4
REDMINE_MEMCACHED=memcached
_EOF_
chmod go-rwx docker-env
- catに指定する _EOF_ を"でくくってはいけない。urandamコ...
** playbookの作成 [#y22e4e40]
- Ansibleサーバ上の一般ユーザで実行
- sudoの場合、become_method: sudo
cat << "_EOF_" > pb_redmine_server-redmine.yml
# install redmine
- hosts: redmine_servers
become: true
become_method: su
environment: "{{ proxy_env }}"
vars:
redmine_path: /srv/redmine
tasks:
- name: check facts
fail:
msg: "Not compatible with [{{ ansible_os_family ...
{{ ansible_distribution }} \
{{ ansible_distribution_major_version }}."
when: >
ansible_os_family != 'RedHat'
or ansible_distribution_major_version|int < 7
- name: add docker repo
shell: dnf config-manager --add-repo https://downl...
args:
warn: false
changed_when: false
- name: install RPMs
dnf:
name:
- httpd
- docker-ce
state: latest
- name: set proxy for docker
file: path=/etc/systemd/system/docker.service.d st...
when: proxy_env.http_proxy is defined
- copy:
dest: /etc/systemd/system/docker.service.d/http-...
force: no
content: "[Service]\n \
Environment = \"http_proxy={{ proxy_env.http_p...
\"https_proxy={{ proxy_env.https_proxy }}\"\n"
when: proxy_env.http_proxy is defined
- name: restart Docker
systemd:
name: docker
state: restarted
daemon_reload: yes
enabled: yes
- name: install docker-compose
stat: path=/usr/local/bin/docker-compose
register: result01
- shell: |
curl --location --output /usr/local/bin/docker-c...
$(curl --silent --show-error \
https://api.github.com/repos/docker/compose/...
| grep 'Linux-x86_64"' \
| grep url \
| cut --delimiter='"' --fields=4 \
)
chmod +x /usr/local/bin/docker-compose
args:
warn: false
when: result01.stat.exists == false
- name: "create {{ redmine_path }}"
file: path={{ redmine_path }} state=directory
register: result02
- shell: |
/usr/sbin/matchpathcon {{ redmine_path }}
/usr/sbin/semanage fcontext --add --type contain...
/usr/sbin/restorecon -v {{ redmine_path }}
/usr/sbin/matchpathcon {{ redmine_path }}
args:
warn: false
when: result02.changed == true
- name: create config files
file: path={{ redmine_path }}/config state=directory
- copy:
src: configuration.yml
dest: "{{ redmine_path }}/config/configuration.y...
force: no
- copy:
dest: "{{ redmine_path }}/config/additional_envi...
force: no
content: |
config.cache_store = :mem_cache_store, "memcac...
config.logger = Logger.new("#{Rails.root}/log/...
config.logger.level = Logger::INFO
- copy:
dest: "{{ redmine_path }}/Gemfile.local"
force: no
content: "gem 'dalli'\n "
- file: path={{ redmine_path }}/../mysql/conf.d stat...
- copy:
dest: "{{ redmine_path }}/../mysql/conf.d/redmin...
force: no
content: |
[mysqld]
innodb_buffer_pool_size = 536870912
innodb_log_file_size = 201326592
- name: create a parent dir of svn-repos
file:
path: /var/lib/svn
owner: nobody
group: users
state: directory
mode: 02775
register: result03
- shell: |
/usr/sbin/semanage fcontext -a -t git_rw_content...
/usr/sbin/restorecon -Rv /var/lib/svn
args:
warn: false
when: result03.changed == true
- name: create a parent dir of git-repos
file:
path: /var/lib/git
owner: nobody
group: users
state: directory
mode: 02775
register: result03
- shell: |
/usr/sbin/semanage fcontext -a -t git_rw_content...
/usr/sbin/restorecon -Rv /var/lib/git
args:
warn: false
when: result03.changed == true
- name: docker-compose up
template:
src: docker-compose.yml
dest: "{{ redmine_path }}/docker-compose.yml"
force: no
- template:
src: docker-env
dest: "{{ redmine_path }}/.env"
force: no
mode: 0400
- shell: docker-compose --project-directory {{ redmi...
args:
chdir: "{{ redmine_path }}"
register: result04
changed_when: '" is up-to-date" not in result04.st...
- name: wait for Completed 200 OK
shell: docker container logs redmine 2>/dev/null |...
register: result05
changed_when: false
until: '"Completed 200 OK " in result05.stdout'
retries: 100
delay: 5
- name: set db password file
slurp:
src: "{{ redmine_path }}/.env"
register: result06
- copy:
dest: ~/.my.cnf.org
force: no
mode: 0400
content: "[client]\nuser = redmine\n \
password = {{ result06['content'] | b64decode ...
regex_findall('REDMINE_DB_PASSWORD=(.+)\\n') |...
host = localhost\n"
register: result07
- shell: docker cp ~/.my.cnf.org mysql:root/.my.cnf
when: result07.changed
- name: load default data
shell: docker exec {% if proxy_env.http_proxy is d...
-e HTTP_PROXY={{ proxy_env.http_proxy }} -e HTTP...
redmine bundle exec rake redmine:load_default_da...
register: result08
changed_when: '" is already loaded." not in result...
- name: update roles
shell: |
cat << '_EOQ_' | docker exec -i mysql mysql redm...
UPDATE `roles` SET `permissions` = NULL WHERE `i...
_EOQ_
changed_when: false
- name: insert settings
shell: |
cat << '_EOQ_' | docker exec -i mysql mysql redm...
SELECT count(*) FROM `settings`
_EOQ_
changed_when: false
register: result09
- shell: |
cat settings.sql | docker exec --interactive mys...
docker exec redmine passenger-config restart-app...
when: result09.stdout_lines[1] == "0"
- name: clear rails cache
shell: docker exec {% if proxy_env.http_proxy is d...
-e HTTP_PROXY={{ proxy_env.http_proxy }} -e HTTP...
redmine bundle exec rails runner 'Rails.cache.cl...
changed_when: false
- name: bundle install
shell: docker exec {% if proxy_env.http_proxy is d...
-e HTTP_PROXY={{ proxy_env.http_proxy }} -e HTTP...
redmine bundle install
changed_when: false
- name: restart passenger
shell: docker exec {% if proxy_env.http_proxy is d...
-e HTTP_PROXY={{ proxy_env.http_proxy }} -e HTTP...
redmine passenger-config restart-app /usr/src/re...
changed_when: false
- name: modify httpd.conf for redmine
copy:
dest: /etc/httpd/conf.d/proxy-redmine.conf
force: no
mode: 0644
content: |
<IfModule !proxy_module>
LoadModule proxy_module modules/mod_proxy.so
</IfModule>
<IfModule !proxy_http_module>
LoadModule proxy_http_module modules/mod_pro...
</IfModule>
ProxyPassMatch /git.* !
ProxyPassMatch /svn.* !
ProxyPassMatch /kibana.* !
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
- name: httpd_can_network_connect
shell: /usr/sbin/getsebool httpd_can_network_connect
register: result10
- shell: /usr/sbin/setsebool -P httpd_can_network_co...
when: result10.stdout == 'httpd_can_network_connec...
notify:
- restart Apache
- name: open ports
firewalld:
service: "{{ item }}"
permanent: true
state: enabled
immediate: yes
loop:
- http
- https
- file: path={{ redmine_path }}/../backup state=dire...
- name: backup-redmine-db.service
copy:
dest: /etc/systemd/system/backup-redmine-db.serv...
content: |
[Unit]
Description=backup redmine db
[Service]
Type=oneshot
ExecStart=/bin/sh -c "docker exec mysql mysqld...
| gzip > {{ redmine_path }}/../backup/redmin...
ExecStartPost=/bin/find {{ redmine_path }}/../...
-name "redmine_db_*.sql.gz" -mtime +30 -delete
- name: backup-redmine-db.timer
copy:
dest: /etc/systemd/system/backup-redmine-db.timer
content: |
[Unit]
Description=backup redmine db
[Timer]
OnCalendar=daily
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
- name: backup-redmine-files.service
copy:
dest: /etc/systemd/system/backup-redmine-files.s...
content: |
[Unit]
Description=backup redmine files
[Service]
Type=oneshot
ExecStart=/bin/sh -c "tar -C {{ redmine_path }...
-czf {{ redmine_path }}/../backup/redmine_fi...
files"
ExecStartPost=/bin/find {{ redmine_path }}/../...
-name "redmine_files_*.tar.gz" -mtime +30 -d...
- name: backup-redmine-files.timer
copy:
dest: /etc/systemd/system/backup-redmine-files.t...
content: |
[Unit]
Description=backup redmine files
[Timer]
OnCalendar=daily
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
- name: enable timers
systemd:
name: "{{ item }}"
daemon_reload: yes
enabled: yes
state: started
loop:
- backup-redmine-db.timer
- backup-redmine-files.timer
- name: check
shell: systemctl list-unit-files | egrep "STATE|ba...
changed_when: false
register: result01
- debug: msg="{{ result01.stdout_lines }}"
handlers:
- name: restart Apache
systemd:
name: httpd
state: restarted
daemon_reload: yes
enabled: yes
_EOF_
- docker_composeはRPMパッケージではなく最新版を使う
** playbookの実行 [#x17c57c6]
- Ansibleサーバ上の一般ユーザで実行
- 実行前に文法チェックしよう
ansible-playbook -i inventory.yml pb_redmine_server-redm...
- 問題なければ実効
ansible-playbook -i inventory.yml pb_redmine_server-redm...
** 補足事項 [#nccd8e9f]
+ mysqlコンテナを削除すると、DBデータはどうなる?
ホストの /var/lib/docker/volumes/mysql/_data/ にMySQLの...
+ mysql_native_passwordの指定は必要?
defaultのsha2_passwordにrailsが対応していない場合を考慮...
+ MySQLやmemcashedは、コンテナではなく、ホスト側にrpm導入...
dockerコンテナからホストのプロセスに通信するには、便利...
同一のcompose.ymlファイルに記述されたコンテナは、同一ネ...
+ RedmineのURLに、コンテキストパス(/redmine)を設定できる?
RedmineのWebサイトに紹介されている。dockerコンテナ内のp...
今回は、「基本的に全てのURL要求をredmineコンテナにproxy...
+ MySQLへの設定追加
ホストの/srv/mysql/conf.d/redmine.cnf に永続化されてい...
ファイルに記述する前に、"set global …"コマンドを用いて...
また、slow queryの常時出力設定は不要と考えている。必要...
set global slow_query_log_file = 'slow.log';
set global long_query_time = 5;
set global slow_query_log = ON;
+ Redmine導入用のplaybookに、git用のタスクがあるんだけど
gitリポジトリ用のSELinux設定は、Redmine用のdocker-compo...
+ ログの循環
Apache HTTP Serverのaccess_log, error_logは、logrotated...
Redmineのproduction.logは、additional_environment.rbで...
* Pluginの導入 [#y8a09536]
** playbookの作成 [#p6694df9]
- Ansibleサーバ上の一般ユーザで実行する。
cat << "_EOF_" > pb_redmine_server-plugin.yml
# install redmine plugins
# dependencies: pb_redmine_server-redmine.yml
- hosts: redmine_servers
become: true
become_method: su
environment: "{{ proxy_env }}"
vars:
redmine_path: /srv/redmine
tasks:
- name: check facts
fail:
msg: "Not compatible with [{{ ansible_os_family ...
{{ ansible_distribution }} \
{{ ansible_distribution_major_version }}."
when: >
ansible_os_family != 'RedHat'
or ansible_distribution_major_version|int < 7
- name: check redmine
stat: path={{ redmine_path }}
register: result01
- fail:
msg: "pb_redmine_server.yml has been executed ye...
when: result01.stat.exists == false
- name: install RPMs
dnf:
name:
- git
state: latest
- name: redmine_pivot_table
shell: >
git clone --depth 1
https://github.com/deecay/redmine_pivot_table
./plugins/redmine_pivot_table
args:
chdir: "{{ redmine_path }}"
notify:
- restart Redmine
handlers:
- name: restart Redmine
shell: |
docker exec redmine bundle exec rake redmine:plu...
docker exec redmine passenger-config restart-app...
_EOF_
** playbookの実行 [#d1fba2df]
- Ansibleサーバ上の一般ユーザで実行
ansible-playbook -i inventory.yml pb_redmine_server-plug...
* Gitの導入 [#af224b39]
GitLabは「Redmineとの連携は結構面倒」なのと「リソース(...
** Apache用設定ファイルの作成 [#f8c6ab05]
- Ansibleサーバ上の一般ユーザで実行
cat << "_EOF_" > repos-git.conf
#<IfModule mod_rewrite.c>
# RewriteEngine On
# RewriteCond %{REQUEST_URI} ^/git/?$
# RewriteRule ^/git /gitweb [R=301,L]
## RewriteRule ^/git/$ /gitweb/ [L,R]
#</IfModule>
PerlLoadModule Apache::Authn::Redmine
SetEnv GIT_PROJECT_ROOT /var/lib/git
SetEnv GIT_HTTP_EXPORT_ALL
ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/
<Location /git/>
Order allow,deny
Allow from all
PerlAccessHandler Apache::Authn::Redmine::access_handler
PerlAuthenHandler Apache::Authn::Redmine::authen_handler
AuthType Basic
AuthName Git
# <LimitExcept GET PROPFIND OPTIONS REPORT>
# SSLRequireSSL
# </LimitExcept>
# for Redmine Authentication
RedmineDSN "DBI:mysql:database=redmine;host=127.0.0.1"
RedmineDbUser "redmine"
RedmineDbPass ""
RedmineGitSmartHttp yes
Require valid-user
# SetEnvIf Request_URI "^/git/$" allow
# Order allow,deny
# Allow from env=allow
# Satisfy any
</Location>
_EOF_
- contextpath"/git"ではなく、VirtualHostにしてもいい。
** playbookの作成 [#t40d7aae]
- Ansibleサーバ上の一般ユーザで実行
- sudoの場合、become_method: sudo
cat << "_EOF_" > pb_redmine_server-git.yml
# install git
# dependencies: pb_redmine_server-redmine.yml
- hosts: redmine_servers
become: true
become_method: su
environment: "{{ proxy_env }}"
vars:
redmine_path: /srv/redmine
tasks:
- name: check facts
fail:
msg: "Not compatible with [{{ ansible_os_family ...
{{ ansible_distribution }} \
{{ ansible_distribution_major_version }}."
when: >
ansible_os_family != 'RedHat'
or ansible_distribution_major_version|int < 7
- name: check redmine
stat: path={{ redmine_path }}
register: result01
- fail:
msg: "pb_redmine_server.yml has been executed ye...
when: result01.stat.exists == false
- name: install RPMs
dnf:
name:
- httpd
- git
- mod_perl
- perl-Digest-SHA
- perl-DBI
- perl-DBD-mysql
# - gitweb
state: latest
- name: modify apache user for git
user: name=apache groups=users append=yes
notify:
- restart Apache
- name: set env for git
file: path=/etc/systemd/system/httpd.service.d sta...
- copy:
dest: /etc/systemd/system/httpd.service.d/git.conf
force: no
content: "[Service]\nUMask=002\n"
notify:
- restart Apache
- name: copy Redmine.pm
file: path=/etc/httpd/Apache/Authn state=directory
- shell: docker cp redmine:/usr/src/redmine/extra/sv...
- name: create repos-git.conf
copy:
src: repos-git.conf
dest: /etc/httpd/conf.d/repos-git.conf
force: no
mode: 0640
- slurp:
src: "{{ redmine_path }}/.env"
register: result03
- lineinfile:
dest: /etc/httpd/conf.d/repos-git.conf
regexp: "^ RedmineDbPass"
line: " RedmineDbPass {{ result03['content'] | ...
| regex_findall('REDMINE_DB_PASSWORD=(.+)\\n')...
notify:
- restart Apache
# - name: modify gitweb
# lineinfile:
# dest: /etc/httpd/conf.d/git.conf
# regexp: '^Alias /git /var/www/git$'
# line: 'Alias /gitweb /var/www/git'
- file: path={{ redmine_path }}/../backup state=dire...
- name: backup-git-repos.service
copy:
dest: /etc/systemd/system/backup-git-repos.service
content: |
[Unit]
Description=backup git repositories
[Service]
Type=oneshot
ExecStart=/bin/sh -c "tar -C /var/lib/git \
-czf {{ redmine_path }}/../backup/git_repos_...
."
ExecStartPost=/bin/find {{ redmine_path }}/../...
-name "git_repos_*.tar.gz" -mtime +30 -delete
- name: backup-git-repos.timer
copy:
dest: /etc/systemd/system/backup-git-repos.timer
content: |
[Unit]
Description=backup git repositories
[Timer]
OnCalendar=daily
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
- name: enable timers
systemd:
name: "{{ item }}"
daemon_reload: yes
enabled: yes
state: started
loop:
- backup-git-repos.timer
- name: check
shell: systemctl list-unit-files | egrep "STATE|ba...
changed_when: false
register: result01
- debug: msg="{{ result01.stdout_lines }}"
handlers:
- name: restart Apache
systemd:
name: httpd
state: restarted
daemon_reload: yes
enabled: yes
_EOF_
** playbookの実行 [#ie6760c5]
- Ansibleサーバ上の一般ユーザで実行
ansible-playbook -i inventory.yml pb_redmine_server-git....
* Subversionの導入 [#x030af9c]
Git嫌な人のために、Subversionも入れちゃう。
** Apache用設定ファイルの作成 [#t0ca81c9]
- Ansibleサーバ上の一般ユーザで実行
cat << "_EOF_" > repos-svn.conf
LimitRequestFieldSize 12392
LoadModule perl_module modules/mod_perl.so
PerlLoadModule Apache::Authn::Redmine
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
RequestHeader edit Destination ^https http early
<Location /svn>
LimitXMLRequestBody 0
DAV svn
SVNParentPath /var/lib/svn
SVNListParentPath on
# SVNIndexXSLT "/svnindex/svnindex.xsl"
# SVNPathAuthz off
# http://www.redmine.org/boards/2/topics/7593
AuthType Basic
AuthName Subversion
PerlAccessHandler Apache::Authn::Redmine::access_handler
PerlAuthenHandler Apache::Authn::Redmine::authen_handler
RedmineDSN "DBI:mysql:database=redmine;host=127.0.0.1"
RedmineDbUser "redmine"
RedmineDbPass ""
## Optional where clause (fulltext search would be slo...
## database dependant).
# RedmineDbWhereClause "and exists (select * from group...
#where users.id = groups_users.user_id and groups_users....
#= (select id from users where type = 'Group' and lastname
#= 'committers'));"
## Optional credentials cache size
# RedmineCacheCredsMax 50
SetEnvIf REQUEST_URI "^/svn/?$" parent
<RequireAny>
Require env parent
Require valid-user
</RequireAny>
</Location>
_EOF_
- contextpath"/svn"ではなく、VirtualHostにしてもいい。
** playbookの作成 [#x639382d]
- Ansibleサーバ上の一般ユーザで実行
- sudoの場合、become_method: sudo
cat << "_EOF_" > pb_redmine_server-svn.yml
# install svn
# dependencies: pb_redmine_server-redmine.yml
- hosts: redmine_servers
become: true
become_method: su
environment: "{{ proxy_env }}"
vars:
redmine_path: /srv/redmine
tasks:
- name: check facts
fail:
msg: "Not compatible with [{{ ansible_os_family ...
{{ ansible_distribution }} \
{{ ansible_distribution_major_version }}."
when: >
ansible_os_family != 'RedHat'
or ansible_distribution_major_version|int < 7
- name: check redmine
stat: path={{ redmine_path }}
register: result01
- fail:
msg: "pb_redmine_server.yml has been executed ye...
when: result01.stat.exists == false
- name: install RPMs
dnf:
name:
- httpd
- subversion
- mod_dav_svn
- mod_perl
- perl-Digest-SHA
- perl-DBI
- perl-DBD-mysql
state: latest
- name: modify apache user for svn
user: name=apache groups=users append=yes
notify:
- restart Apache
- name: set env for svn
file: path=/etc/systemd/system/httpd.service.d sta...
- copy:
dest: /etc/systemd/system/httpd.service.d/svn.conf
force: no
content: "[Service]\nEnvironment=LANG='ja_JP.UTF...
notify:
- restart Apache
- name: copy Redmine.pm
file: path=/etc/httpd/Apache/Authn state=directory
- shell: docker cp redmine:/usr/src/redmine/extra/sv...
- name: create repos-svn.conf
copy:
src: repos-svn.conf
dest: /etc/httpd/conf.d/repos-svn.conf
force: no
mode: 0640
- slurp:
src: "{{ redmine_path }}/.env"
register: result03
- lineinfile:
dest: /etc/httpd/conf.d/repos-svn.conf
regexp: "^ RedmineDbPass"
line: " RedmineDbPass {{ result03['content'] | ...
| regex_findall('REDMINE_DB_PASSWORD=(.+)\\n')...
notify:
- restart Apache
- file: path={{ redmine_path }}/../backup state=dire...
- name: backup-svn-repos.service
copy:
dest: /etc/systemd/system/backup-svn-repos.service
content: |
[Unit]
Description=backup svn repositories
[Service]
Type=oneshot
ExecStart=/bin/sh -c "tar -C /var/lib/svn \
-czf {{ redmine_path }}/../backup/svn_repos_...
."
ExecStartPost=/bin/find {{ redmine_path }}/../...
-name "svn_repos_*.tar.gz" -mtime +30 -delete
- name: backup-svn-repos.timer
copy:
dest: /etc/systemd/system/backup-svn-repos.timer
content: |
[Unit]
Description=backup svn repositories
[Timer]
OnCalendar=daily
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
- name: enable timers
systemd:
name: "{{ item }}"
daemon_reload: yes
enabled: yes
state: started
loop:
- backup-svn-repos.timer
- name: check
shell: systemctl list-unit-files | egrep "STATE|ba...
changed_when: false
register: result01
- debug: msg="{{ result01.stdout_lines }}"
handlers:
- name: restart Apache
systemd:
name: httpd
state: restarted
daemon_reload: yes
enabled: yes
_EOF_
** playbookの実行 [#afa695a9]
- Ansibleサーバ上の一般ユーザで実行
ansible-playbook -i inventory.yml pb_redmine_server-svn....
* 管理作業 [#bed50813]
** Gitリポジトリの新規作成 [#x46884bc]
- Ansibleで実施すると簡便か?
- Ansibleサーバ上の一般ユーザで実行。対象サーバの実行アカ...
cat << "_EOF_" > pb_create_git_repository.yml
# create git repository
- hosts: all
vars:
gitrepos_path: /var/lib/git
ansible_user: user #as your own
ansible_password: user #as your own
vars_prompt:
- name: repos_name
prompt: "Enter the reposotory name. "
default: myrepos.git
private: no
tasks:
- debug:
msg: "The repos_name is {{ repos_name }}."
- fail: msg="The string you enter is not a valid rep...
when: repos_name is not regex("[a-z].+\..+")
- stat: path="{{ gitrepos_path }}/{{ repos_name }}"
register: result00
- fail: msg="Already exists."
when: result00.stat.exists == true
- shell: groups
register: result01
- debug:
msg: "Your groups is {{ result01.stdout.split(' ...
- fail: msg="You do not have permission to create a ...
when: "'users' not in result01.stdout.split(' ')"
- shell: "git init --bare --shared {{ gitrepos_path ...
- shell: >
git update-server-info
&& cp hooks/post-update.sample hooks/post-update
&& git config --local core.ignorecase false
&& git config --local core.quotepath false
args:
chdir: "{{ gitrepos_path }}/{{ repos_name }}/"
# - copy:
# dest: "{{ gitrepos_path }}/{{ repos_name }}/clo...
# content: "<a href=\"http://{{ inventory_hostnam...
# >http://{{ inventory_hostname }}/git/{{ repos...
# - copy:
# dest: "{{ gitrepos_path }}/{{ repos_name }}/des...
# content: "((TODO: descriptionファイルへ、リポジ...
# - copy:
# dest: "{{ gitrepos_path }}/{{ repos_name }}/REA...
# content: "<h3>概要</h3>\n \
# ((TODO: ここにはリポジトリの説明を書...
# <h3>ルール・留意点</h3>\n \
# ((TODO: ここにはリポジトリ利用に際し...
# <h3>問い合わせ先・管理者</h3>\n \
# ((TODO: ここにはリポジトリに対しての...
# <hr />\n \
# ※TODO: このテンプレートにこだわらず、...
_EOF_
- Ansibleサーバ上の一般ユーザで実行
ansible-playbook -i its.jomura.net, pb_create_git_reposi...
-- リポジトリ名を問われるので、入力する
Enter the repository name. [myrepos.git]:
- または、"-e"オプションでリポジトリ名を指定することもで...
ansible-playbook -i its.jomura.net, -e repos_name=myrepo...
- リポジトリ名の"."より前は、Redmineプロジェクトの"識別子...
- /var/lib/git/{リポジトリ名}/ の直下に、下記のファイルを...
++ README.html : リポジトリの説明をHTMLで記述する。
++ description : リポジトリの説明を簡単に1行程度で記述す...
++ cloneurl : リポジトリアクセス用のURLを記述する。有用。
ページ名: