プロジェクト

全般

プロフィール

機能 #14

GitBucket 2.1のRPMを作成する

高橋 徹5年以上前に追加. ほぼ5年前に更新.

ステータス:
終了
優先度:
通常
担当者:
カテゴリ:
-
対象バージョン:
-
開始日:
2014/07/20
期日:
進捗率:

100%

予定工数:

説明

GitBucket 2.1のRPMを作成します。
GitBucketの入手先(GitHub)は次のURLです。
https://github.com/takezoe/gitbucket

このリポジトリのcontribには、Red Hat Enterprise Linux用のRPM作成に使うSPECファイル、サービス起動のinitファイル、設定ファイルが登録されていますが、rootユーザーで動く仕様となっています。

そこで、Jenkinsのようにrootではなく特定のユーザー権限で動くようにRPMを作成します。


関連するチケット

関連している 機能 #54: GitBucket 3.11のRPMを、H2 database migrationツールを含めて作成する却下2016/02/28

履歴

#1 高橋 徹5年以上前に更新

  • ステータス新規 から 進行中 に変更
  • 進捗率0 から 50 に変更

まずは、GitHubリポジトリより次のファイルを入手します。

  • gitbucket.war (Javaバイトコード)
  • gitbucket-2.1.tar.gz (ソースファイル)
  • gitbucket.spec (RPMビルド用定義ファイル)
  • gitbucket.conf (GitBucket実行時の設定ファイル)
  • gitbucket.init (GitBucketをservice起動するためのスクリプトファイル)

それぞれRPMビルド用に配置します。

$HOME/rpm
  +-- SPECS
  |     +-- gitbucket.spec
  +-- SOURCES
        +-- gitbucket.war
        +-- gitbucket-2.1.tar.gz
        +-- gitbucket.conf
        +-- gitbucket.ini

GitBucketのcontribをほぼそのままでRPM作成(rootユーザー実行)

--- gitbucket.spec      2014-07-20 21:23:47.303501900 +0900
+++ rpm/SPECS/gitbucket.spec    2014-07-20 21:27:18.326450470 +0900
@@ -1,6 +1,6 @@
 Name:          gitbucket
 Summary:       GitHub clone written with Scala.
-Version:       1.7
+Version:       2.1
 Release:       1%{?dist}
 License:       Apache
 URL:           https://github.com/takezoe/gitbucket
@@ -40,6 +40,9 @@

 %changelog
+* Sun Jul 20 2014 Toru Takahashi <torutk at gmail.com>
+- Version bump to v2.1.
+
 * Mon Oct 28 2013 Jiri Tyr <jiri_DOT_tyr at gmail.com>
 - Version bump to v1.7.

RPMビルドを実行します。

~$ rpmbuild -ba rpm/SPECS/gitbucket.spec
  :

RPMおよびSRPMが生成されます。

$HOME/rpm
  +-- RPMS
  |     +-- noarch
  |           +-- gitbucket-2.1-1.el6.noarch.rpm
  +-- SRPMS
        +-- gitbucket-2.1-1.el6.src.rpm

生成されたRPMをインストールします。

~$ sudo rpm -Uvh rpm/RPMS/noarch/gitbucket-2.1-1.el6.noarch.rpm
準備中...                ########################################### [100%]
   1:gitbucket              ########################################### [100%]
~$

次のファイルがインストールされました。

~$ rpm -ql gitbucket
/etc/init.d/gitbucket
/etc/sysconfig/gitbucket
/usr/share/gitbucket/lib/gitbucket.war
/var/log/gitbucket/run.log
~$

手動でgitbucketを実行します。

~$ sudo service gitbucket start

gitbucketのログは、/var/log/gitbucket/run.log に生成されます。
gitbucketのプロセスIDは、/var/run/gitbucket.pid に生成されます。
gitbucketのデータは、/var/lib/gitbucket/ に生成されます。data.h2.db, data.lock.db, version といったファイルが見受けられます。

#2 高橋 徹5年以上前に更新

gitbucketをrootユーザーではなくgitbucketユーザーで動かすために必要なことを調べる

rootで動くgitbucketをインストールした後、これをgitbucketユーザーで動かすために必要な修正をしていきます。
修正が完了した時点でgitbucket.specファイルほかを修正していきます。

#3 高橋 徹5年以上前に更新

gitbucketをrootユーザーではなくgitbucketユーザーで動かすために必要なことを調べる

Jenkinsが同じくwarファイルをjavaで実行するタイプですが、rootユーザーではなくjenkinsユーザーで実現しているので、Jenkinsの起動スクリプトを参考にします。
https://github.com/jenkinsci/jenkins/blob/master/rpm/SOURCES/jenkins.init.in

rootで動くgitbucketをインストールした後、これをgitbucketユーザーで動かすために必要な修正をしていきます。
修正が完了した時点でgitbucket.specファイルほかを修正していきます。

gitbucketユーザー/グループの作成

~$ sudo groupadd -r gitbucket
~$ sudo useradd -g gitbucket -s /bin/false -r -c "GitBucket SCM Server" -d /var/lib/gitbucket gitbucket

  • jenkinsの設定に倣ってユーザーのシェルを/bin/falseにしたけど、su gitbucket -c "コマンド"がスカって起動しません。調べると、
    • /bin/false はシェルを通じて一切の操作ができない偽シェル(su <ユーザー> -c "コマンド"も操作できない模様)。daemonで起動する場合はシェルを通じないかも(jenkinsのinitスクリプトではdaemon関数でコマンドを実行していた)。

gitbucketのログディレクトリ/ファイルの所有者変更

~$ sudo chown -R gitbucket.gitbucket /var/log/gitbucket

gitbucket起動スクリプト(/etc/init.d/gitbucket)でコマンドをgitbucketユーザーで実行する変更
@@ -41,7 +41,7 @@
        fi

        # Run the Java process
-       daemon --user gitbucket --pidfile ${PID_FILE} "GITBUCKET_HOME=${GITBUCKET_HOME} java $GITBUCKET_JVM_OPTS -jar $GITBUCKET_WAR_FILE $START_OPTS >>$LOG_FILE 2>&1 &" 
+       GITBUCKET_HOME="${GITBUCKET_HOME}" java $GITBUCKET_JVM_OPTS -jar $GITBUCKET_WAR_FILE $START_OPTS >>$LOG_FILE 2>&1 &
        RETVAL=$?

        # Store PID of the Java process into a file
  • 最初 su gitbucket -c "..." で実行しようとしましたが、gitbucketユーザーのシェルが偽シェル(/sbin/false)だと駄目だったのでdaemon関数で実行してみました。

起動しましたが、serviceからstopができません。PIDファイルが空です。

gitbucket起動スクリプト(/etc/init.d/gitbucket)でdaemon関数で起動したjavaプロセスのPIDを取得する変更

@@ -46,6 +46,13 @@

        # Store PID of the Java process into a file
        echo $! > $PID_FILE
+       /bin/ps hww -u gitbucket -o sess,ppid,pid,cmd | \
+       while read sess ppid pid cmd; do
+               [ "$ppid" = 1 ] || continue
+               echo "$cmd" | grep $GITBUCKET_WAR_FILE > /dev/null
+               [ $? = 0 ] || continue
+               echo $pid > "$PID_FILE" 
+       done

        if [ $RETVAL -eq 0 ] ; then
                success "GitBucket startup" 

gitbucketのデータは、/var/lib/gitbucketの下に作成されます。ここの所有権をgitbucketユーザーに変更します。

~$ sudo chown -R gitbucket.gitbucket /var/lib/gitbucket

#4 高橋 徹5年以上前に更新

実効ユーザーを変更したRPMを作成するための修正

SPECファイルにgitbucketユーザー・グループ作成とファイルのパーミッション指定を追加

@@ -1,7 +1,7 @@
 Name:          gitbucket
 Summary:       GitHub clone written with Scala.
 Version:       2.1
-Release:       1%{?dist}
+Release:       2%{?dist}
 License:       Apache
 URL:           https://github.com/takezoe/gitbucket
 Group:         System/Servers
@@ -26,6 +26,25 @@
 %{__install} -m 0644 %{SOURCE2} %{buildroot}%{_sysconfdir}/sysconfig/%{name}
 touch %{buildroot}%{_localstatedir}/log/%{name}/run.log

+%pre
+/usr/sbin/groupadd -r gitbucket &> /dev/null || :
+/usr/sbin/useradd -g gitbucket -s /bin/false -r -c "GitBucket GitHub clone" -d %{_sharedstatedir}/%{name} gitbucket &> /dev/null || :
+
+%post
+/sbin/chkconfig --add gitbucket
+
+%preun
+if [ "$1" = 0 ]; then
+  /sbin/service gitbucket stop > /dev/null 2>&1
+  /sbin/chkconfig --del gitbucket
+fi
+exit 0
+
+%postun
+if [ "$1" -ge 1 ]; then
+  /sbin/service gitbucket restart > /dev/null 2>&1
+fi
+exit 0

 %clean
 [ "%{buildroot}" != / ] && %{__rm} -rf "%{buildroot}" 
@@ -34,12 +53,16 @@
 %files
 %defattr(-,root,root,-)
 %{_datarootdir}/%{name}/lib/%{name}.war
-%{_sysconfdir}/init.d/%{name}
-%config %{_sysconfdir}/sysconfig/%{name}
-%{_localstatedir}/log/%{name}/run.log
+%config %{_sysconfdir}/init.d/%{name}
+%config(noreplace) %{_sysconfdir}/sysconfig/%{name}
+%attr(0755,gitbucket,gitbucket) %{_sharedstatedir}/%{name}
+%attr(0750,gitbucket,gitbucket) %{_localstatedir}/log/%{name}

 %changelog
+* Mon Jul 21 2014 Toru Takahashi <torutk at gmail.com>
+- execute as gitbucket user
+
 * Sun Jul 20 2014 Toru Takahashi <torutk at gmail.com>
 - Version bump to v2.1.

#5 高橋 徹5年以上前に更新

  • ステータス進行中 から 解決 に変更
  • 進捗率50 から 80 に変更

本作業の成果物は、GitBucketページに上げています。

#6 高橋 徹約5年前に更新

Gitbucket 2.4.1がリリースされたので、RPMパッケージを作成しました。

  • https://github.com/takezoe/gitbucket/releases からソースコードとwarをダウンロードし、~/rpm/SOURCESにコピー
  • 2.1のSPECファイルをバージョンを2.4.1に修正
  • ソースコードを作業ディレクトリに展開し、contrib/gitbucket.{conf,init}を取り出し~/rpm/SOURCESにkピー
  • rpmbuild実行
  • 出来たRPMをインストール
  • サービス実行
    ~$ sudo service gitbucket start
    ~$
    

    あれ、なにもメッセージが出ません。おかしい。/etc/init.d/gitbucketを直接実行
    ~$ cd /etc/init.d
    inti.d$ sudo ./gitbucket start
    init.d$
    

    同じく。gitbucketに片っ端からecho文を埋めてみると、
     13 set -e
     14
     15 [ -f /etc/rc.d/init.d/functions ] && source /etc/rc.d/init.d/functions  # RedHat
    

    15行目より後に入れたecho文が出ない。
    → set -e について調べてみた

set -e での動作を想定していないライブラリを . (ドット) コマンド や source コマンドで読み込んだときに使えない。

http://qa.atmarkit.co.jp/q/2813
とあった。set -eを削除するとメッセージが出るようになった。

現状はjavaプロセスがrootで実行される。gitbucketユーザーで実行するために、/etc/rc.d/init.d/functionsで定義されるdaemonファンクションを使用してみました。

GITBUCKET_HOME="${GITBUCKET_HOME}" daemon --user=gitbucket java $GITBUCKET_JVM_OPTS -jar $GITBUCKET_WAR_FILE $START_OPTS >>$LOG_FILE 2>&1 &

/var/lib/gitbucketのパーミッションがrootだと動かないのでgitbucketに変更したら動きました。

#7 高橋 徹約5年前に更新

service gitbucket stopで停止しない

/etc/init.d/gitbucket の起動部分を抜粋

 60   GITBUCKET_HOME="${GITBUCKET_HOME}" daemon --user=gitbucket java $GITBUCKET    _JVM_OPTS -jar $GITBUCKET_WAR_FILE $START_OPTS >>$LOG_FILE 2>&1 &
 61   RETVAL=$?
 62
 63   echo $! > $PID_FILE

起動するプロセスをps auxから抜粋

~$ ps aux|grep gitbucket
root      1194  /bin/bash /etc/rc3.d/S60gitbucket start
root      1203  runuser -s /bin/bash gitbucket -c ulimit -S -c 0 >/dev/null 2>&1 ; java -Dmail.smtp.starttls.enable=true -jar /usr/share/gitbucket/lib/gitbucket.war --port=8080 --host=0.0.0.0
496       1205  bash -c ulimit -S -c 0 >/dev/null 2>&1 ; java -Dmail.smtp.starttls.enable=true -jar /usr/share/gitbucket/lib/gitbucket.war --port=8080 --host=0.0.0.0
496       1206  java -Dmail.smtp.starttls.enable=true -jar /usr/share/gitbucket/lib/gitbucket.war --port=8080 --host=0.0.0.0

このとき、/var/run/gitbucketの中は、1194 となっていた。これはgitbucketプロセスではなく、gitbucketプロセスを起動するシェルスクリプトのPIDとなっている。

daemon functionに渡す--pidfileオプションは参照用でそのファイルを生成してPIDを書き込んではくれない!

@@ -60,8 +60,6 @@
        GITBUCKET_HOME="${GITBUCKET_HOME}" daemon --user=gitbucket java $GITBUCKET_JVM_OPTS -jar $GITBUCKET_WAR_FILE $START_OPTS >>$LOG_FILE 2>&1 &
        RETVAL=$?

-       echo $! > $PID_FILE
-
        if [ $RETVAL -eq 0 ] ; then
                success "Success" 
        else
@@ -77,11 +75,10 @@
        echo -n $"Stopping GitBucket server: " 

        # Run the Java process
-       kill $(cat $PID_FILE 2>/dev/null) >>$LOG_FILE 2>&1
+       pkill -f $GITBUCKET_WAR_FILE >>$LOG_FILE 2>&1
        RETVAL=$?

        if [ $RETVAL -eq 0 ] ; then
-               rm -f $PID_FILE
                success "GitBucket stopping" 
        else
                failure "GitBucket stopping" 

#8 高橋 徹約5年前に更新

GitBucketの起動制御スクリプトの再構築

CentOS 6でGitBucketの起動制御スクリプトを使えるようにするため、リポジトリの元ネタから再度修正を開始します。
https://github.com/takezoe/gitbucket/blob/master/contrib/gitbucket.init

これをCentOS 6で動かすと次の行でエラーとなりました。

if [ `isMac` ]; then

CentOS 6にはisMacというコマンドがないためです。gitbucket.initはこのスクリプトは、RedHat/Ubuntu/Mac OS X共用になっています。ファイル先頭のコメント部分を抜き出します。
# RedHat: /etc/rc.d/init.d/gitbucket
# Ubuntu: /etc/init.d/gitbucket
# Mac OS/X: /Library/StartupItems/GitBucket

しかし、スクリプト中にif文で切り分けを入れる作りでは、3つの環境を持っていてすべてで確認しながら修正作業をする必要があります。すべての環境を持っていることは稀で、持っていたとしても甚だ手間がかかります。実際、上述のようにRedHat系のCentOSにはないコマンドを実行するコードが入ってしまっています。スクリプトは環境ごとに分けるべきでしょう。

ということで、まずRedHat系専用のスクリプトにします。gitbucketのリポジトリを見ると

gitbuckt
  +-- contrib
  :     +-- linux
  :     |     +-- redhat
  :     |           +-- gitbucket.spec
  :     +-- macosx
  :     |     +-- makePlist
  :     +-- README.md
  :     +-- gitbucket.conf
  :     +-- gitbucket.init
  :     +-- install

となっているので、RedHat専用にする起動制御スクリプトは、contrib/linux/redhat/に置くのが好ましいでしょう。そこで、contrib/gitbucket.init を、contrib/linux/redhat/gitbucket.init にコピーしこれを変更していきます。

  • Ubuntu/MacOS用コードの削除
    -# Ubuntu: /etc/init.d/gitbucket
    -# Mac OS/X: /Library/StartupItems/GitBucket
      :
    -[ -f /etc/rc.common ] && source /etc/rc.common # Mac OS/X
      :
    -## MacOS proxies for System V service hooks:
    -StartService() {
    -       start
    -}
    -StopService() {
    -       stop
    -}
    -
    -RestartService() {
    -       restart
    -}
    -
    -
    -if [ `isMac` ]; then
    -  RunService "$1" 
    -else
      :
    -fi
    
  • set -eの削除(前に述べたsource /etc/rc.d/init.d/functions を機能させるための修正)
    -set -e
    -
    
  • gitbucketユーザーで実行(前に述べた修正)
    -       GITBUCKET_HOME="${GITBUCKET_HOME}" java $GITBUCKET_JVM_OPTS -jar $GITBUCKET_WAR_FILE $START_OPTS >>$LOG_FILE 2>&1 &
    +       GITBUCKET_HOME="${GITBUCKET_HOME}" daemon --user=gitbucket java $GITBUCKET_JVM_OPTS -jar $GITBUCKET_WAR_FILE $START_OPTS >>$LOG_FILE 2>&1 &
    
  • pidファイルによるサービス(プロセス)終了の制御ができないため代替方法
    -PID_FILE=/var/run/gitbucket.pid
      :
    -       echo $! > $PID_FILE
    -
      :
    -       kill $(cat $PID_FILE 2>/dev/null) >>$LOG_FILE 2>&1
    +       pkill -f gitbucket.war >>$LOG_FILE 2>&1
      :
    -               rm -f $PID_FILE
      :
                status)
    -                    status -p $PID_FILE java
    +                    pgrep -f gitbucket.war >> $LOG_FILE 2>&1
                         RETVAL=$?
    +                    if [ $RETVAL -eq 0 ]; then
    +                            echo $"GitBucket is running...." 
    +                    else
    +                            echo $"GitBucket is stopped" 
                         ;;
    

ここまでの修正でサービス起動制御スクリプトを実行すると次のようになります。

~$ sudo service gitbucket status
which: no success in (/sbin:/usr/sbin:/bin:/usr/bin)
which: no failure in (/sbin:/usr/sbin:/bin:/usr/bin)
GitBucket is stopped

これは、次のスクリプト記述が原因です。

if [ -z "$(which success)" ]; then
    function success {
        printf "%b\n" "$GREEN $* $OFF" 
    }
fi
if [ -z "$(which failure)" ]; then
    function failure {
        printf "%b\n" "$RED $* $OFF" 
    }
fi

successとfailureは、/etc/rc.d/init.d/functionsスクリプトで定義されるシェル関数です。whichコマンドでパスを取得することができません。しかし、このスクリプト記述はsuccessとfailureがコマンドである想定で書かれています。RedHat系専用スクリプトでは、ばっさり削除してしまいます。

-if [ -z "$(which success)" ]; then
-    function success {
-        printf "%b\n" "$GREEN $* $OFF" 
-    }
-fi
-if [ -z "$(which failure)" ]; then
-    function failure {
-        printf "%b\n" "$RED $* $OFF" 
-    }
-fi

起動に失敗しても、スクリプト上は成功として表示されてしまいます。次のスクリプト部分が課題です。

GITBUCKET_HOME="${GITBUCKET_HOME}" daemon --user=gitbucket java $GITBUCKET \
   _JVM_OPTS -jar $GITBUCKET_WAR_FILE $START_OPTS >>$LOG_FILE 2>&1 &
RETVAL=$?
if [ $RETVAL -eq 0 ] ; then
  success "Success" 
else
  failure "Exit code $RETVAL" 
fi

バックグラウンド実行(末尾に'&'をつけて実行)した場合、コマンド実行結果('$?')は常に0(成功)となります。
そこで、daemonでバックグラウンド実行後、一定時間経過待ち1してからpgrepでプロセスを探して結果を判定することにします。
    GITBUCKET_HOME="${GITBUCKET_HOME}" daemon --user=gitbucket java $GITBUCKET    _JVM_OPTS -jar $GITBUCKET_WAR_FILE $START_OPTS >>$LOG_FILE 2>&1 &
+   sleep 3
+   pgrep -f $GITBUCKET_WAR_FILE >> $LOG_FILE 2>&1
    RETVAL=$?

1 本当はプロセスが立ち上がったことを確認したかったのですが、うまいやり方が見つからずsleepにしてしまいました。

#9 高橋 徹ほぼ5年前に更新

  • ステータス解決 から 終了 に変更
  • 進捗率80 から 100 に変更

【棚卸し】この修正を、gitbucketのgithubリポジトリからフォークを作成して、ブランチにコミット
https://github.com/torutk/gitbucket/commit/676670e9e3a1666404bedb4cccf54de2773ad0b9

プルリクエストを発行して、その後取り込んでいただきました。

#10 高橋 徹ほぼ4年前に更新

  • 関連している 機能 #54: GitBucket 3.11のRPMを、H2 database migrationツールを含めて作成する を追加

他の形式にエクスポート: Atom PDF

クリップボードから画像を追加 (サイズの上限: 1 GB)