DockerでScrewdriver環境を構築

# はじめに
Dockerを使ってScrewdriverの環境を構築しました。

# 実行環境
OS：MacOS Monterey 12.3.1
Docker：Docker Desktop for Mac 4.7.1
Docker Image：centos7

# 事前準備
## GitHubの設定
### OAuth Appsを登録
「Settings」の「Developer settings」から「OAuth Apps」を登録します。
「New OAuth App」を押下し、各項目を入力します。

Application name
→任意

Homepage URL
→http://sd.screwdriver.cd:4200

Application description
→任意

Authorization callback URL
→http://sd.screwdriver.cd:9001/v4/auth/login

## 自端末での準備
### hostsファイルにドメイン名を紐付け
自端末のhostsファイルに「127.0.0.1 sd.screwdriver.cd」を追加し、
これから構築するScrewdriverのドメイン名を紐付けます。

```shell
% sudo vim /etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1       localhost
127.0.0.1 sd.screwdriver.cd # ⇦を追加
# ・・・
```

### CentOSを起動
Dockerイメージをプルし、CentOSを起動します。
構築したScrewdriverにアクセスするために4200、9001ポートをマッピングしておきます。

```shell
% docker pull centos:7
% docker run --name screwdriver-centos -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro -p 4200:4200 -p 9001:9001 -d centos:7
```

## Docker内での準備
### Gitをインストール
Screwdriverに必要なリポジトリをクローンするため、Gitをインストールします。

```shell
sh-4.2# yum install -y git-all
```

バージョンを確認出来れば成功です。

```shell
sh-4.2# git --version
git version 1.8.3.1
```

### node.jsとnpmをインストール
[公式より](https://docs.screwdriver.cd/ja/about/contributing/getting-started-developing)Node v12.0.0以上が必要と記載がありますので、node.jsとnpmをインストールします。

```shell
sh-4.2# curl -fsSL https://rpm.nodesource.com/setup_16.x | bash -
sh-4.2# yum install -y nodejs

```shell
sh-4.2# node -v
v16.15.0
sh-4.2# npm -v
8.5.5
```

# Screwdriver環境を構築
[公式ページ](https://docs.screwdriver.cd/ja/about/contributing/getting-started-developing#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E7%92%B0%E5%A2%83%E3%81%AB%E6%A7%8B%E7%AF%89)を参考にScrewdriver環境を構築します。

## リポジトリをクローン
screwdriver-cdのリポジトリをクローンします。

```shell
sh-4.2# cd opt
sh-4.2# git clone https://github.com/screwdriver-cd/ui.git
sh-4.2# git clone https://github.com/screwdriver-cd/screwdriver.git
sh-4.2# git clone https://github.com/screwdriver-cd/store.git
```

## 自分のIPアドレスを確認
screwdriverの設定ファイルに自身のIPアドレスを設定する必要があるため、
自分のIPアドレスを[確認](https://www.cman.jp/network/support/go_access.cgi)しておきます。

## 秘密鍵と公開鍵を生成
screwdriver、storeリポジトリに追加する設定ファイルに使う秘密鍵と公開鍵を生成します。

```shell
sh-4.2# openssl genrsa -out jwt.pem 2048
Generating RSA private key, 2048 bit long modulus
...................................................................+++
..............................................................+++
e is 65537 (0x10001)
```

```shell
sh-4.2# openssl rsa -in jwt.pem -pubout -out jwt.pub
writing RSA key
```

```shell
sh-4.2# ls
jwt.pem  jwt.pub
```

## 各リポジトリに設定ファイル類を追加
### uiリポジトリ
#### ui/config/local.jsを追加

```shell
sh-4.2# vi ui/config/local.js
let SDAPI_HOSTNAME;
let SDSTORE_HOSTNAME;

SDAPI_HOSTNAME = 'http://sd.screwdriver.cd:9001';
SDSTORE_HOSTNAME = 'http://sd.screwdriver.cd:9002';

module.exports = {
  SDAPI_HOSTNAME,
  SDSTORE_HOSTNAME
};
```

### screwdriverリポジトリ
#### mw-dataディレクトリを作成

```shell
sh-4.2# mkdir screwdriver/mw-data
```

#### screwdriver/config/local.yaml
authセクションに作成しておいた秘密鍵・公開鍵。
http、ecosystemセクションに自分のIPアドレス。
scmsセクションにGitHubの認証情報とOAuth Apps登録時に控えておいたClient ID、Client secretsを設定します。

```shell
sh-4.2# vi screwdriver/config/local.yaml
auth:
    jwtPrivateKey: |
        -----BEGIN RSA PRIVATE KEY-----
        # 秘密鍵の中身
        -----END RSA PRIVATE KEY-----

    jwtPublicKey: |
        -----BEGIN PUBLIC KEY-----
        # 公開鍵の中身
        -----END PUBLIC KEY-----

httpd:
  # Port to listen on
  port: 9001

  # Host to listen on (set to localhost to only accept connections from this machine)
  host: 0.0.0.0

  # Externally routable URI (usually your load balancer or CNAME)
  # This requires to be a routable IP inside docker for executor, see
  # https://github.com/screwdriver-cd/screwdriver/blob/095eaf03e053991443abcbde91c62cfe06a28cba/lib/server.js#L141
  uri: http://（自分のIPアドレス）:9001

ecosystem:
  # Externally routable URL for the User Interface
  ui: http://sd.screwdriver.cd:4200

  # Externally routable URL for the Artifact Store
  store: http://（自分のIPアドレス）:9002

  allowCors: ['http://sd.screwdriver.cd', 'http://（自分のIPアドレス）:9001']

executor:
    plugin: docker
    docker:
        enabled: true
        options:
            docker:
                socketPath: "/var/run/docker.sock"

scms:
    github:
        plugin: github
        config:
            # github
            oauthClientId: OAuth Apps登録時に控えておいたClient ID
            oauthClientSecret: OAuth Apps登録時に控えておいたClient secrets
            secret: GitHubのパスワード
            username: GitHubのユーザー名
            email: 任意のメールアドレス
            privateRepo: false

datastore:
  plugin: sequelize
  sequelize:
    # Type of server to talk to
    dialect: sqlite
    # Storage location for sqlite
    storage: ./mw-data/storage.db
```

### storeリポジトリ
#### mw-dataディレクトリを作成

```shell
sh-4.2# mkdir store/store-data
```

#### store/config/local.yamlを追加

```shell
sh-4.2# vi store/config/local.yaml
auth:
    jwtPublicKey: |
        -----BEGIN PUBLIC KEY-----
        # 公開鍵の中身
        -----END PUBLIC KEY-----

strategy:
    plugin: disk
    disk:
        cachePath: './store-data'
        cleanEvery: 3600000
        partition : 'cache'

httpd:
    port: 9002

ecosystem:
    ui: http://sd.screwdriver.cd:4200
    api: http://sd.screwdriver.cd:9001
    allowCors: ['http://sd.screwdriver.cd']
```

## 各リポジトリで依存関係をインストールして実行
## uiリポジトリ
### 依存関係をインストールして実行（失敗）
uiに移動して依存関係をインストールして実行します。

```shell
sh-4.2# cd ui/
sh-4.2# npm install && npm run start
npm WARN old lockfile 
npm WARN old lockfile The package-lock.json file was created with an old version of npm,

# ・・・

⠴ building... [Babel: ember-ace > applyPatches]node:internal/validators:164
      throw new ERR_INVALID_ARG_TYPE(name, 'Object', value);
      ^

TypeError [ERR_INVALID_ARG_TYPE]: The "options" argument must be of type object. Received an instance of Array
    at ChildProcess.target.send (node:internal/child_process:733:7)
    at Array.forEach (<anonymous>:null:null)
    at dispatchQueuedRequests (/root/ui/node_modules/ember-ace/node_modules/workerpool/lib/WorkerHandler.js:174:21)
    at ChildProcess.<anonymous> (/root/ui/node_modules/ember-ace/node_modules/workerpool/lib/WorkerHandler.js:129:7)
    at ChildProcess.emit (node:events:527:28)
    at ChildProcess.emit (node:domain:475:12)
    at emit (node:internal/child_process:938:14)
    at processTicksAndRejections (node:internal/process/task_queues:84:21)
 {
  code: 'ERR_INVALID_ARG_TYPE'
}
```

上手くいきませんでした。
[こちらのページ](https://github.com/yui/yuidoc/issues/453)より、node.jsのバージョンによって発生しているようです。
node.jsのバージョンを14.15にダウングレードします。

#### node.jsのダウングレード

```shell
sh-4.2# npm install -g n

added 1 package, and audited 2 packages in 1s

found 0 vulnerabilities
```

```shell
sh-4.2# n 14.15
  installing : node-v14.15.5
       mkdir : /usr/local/n/versions/node/14.15.5
       fetch : https://nodejs.org/dist/v14.15.5/node-v14.15.5-linux-x64.tar.xz
     copying : node/14.15.5
   installed : v14.15.5 (with npm 6.14.11)
```

### 依存関係をインストールして実行（成功）
再度実行すると、今度は無事立ち上がりました。

```shell
sh-4.2# npm install && npm run start

# ・・・

Build successful (90081ms) – Serving on http://localhost:4200/

Slowest Nodes (totalTime >= 5%)          | Total (avg)
-----------------------------------------+-----------
Babel: screwdriver-ui (4)                | 26026ms (6506 ms)
Babel: ember-bootstrap (1)               | 6129ms
```

## screwdriverリポジトリ
### 依存関係をインストールして実行（失敗）
screwdriverに移動して依存関係をインストールして実行します。

```shell
sh-4.2# cd /opt/screwdriver/
sh-4.2# npm install && npm run start
```

```shell
/opt/screwdriver/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:57
      throw err;
      ^

Error: /lib64/libstdc++.so.6: version `CXXABI_1.3.8' not found (required by /opt/screwdriver/node_modules/sqlite3/lib/binding/napi-v6-linux-glibc-x64/node_sqlite3.node)
    at Object.Module._extensions..node (internal/modules/cjs/loader.js:1122:18)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (internal/modules/cjs/helpers.js:88:18)
    at Object.<anonymous> (/opt/screwdriver/node_modules/sqlite3/lib/sqlite3-binding.js:4:17)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
```

こちらも上手くいきませんでした。
CXXABI_1.3.8が無いと言ってるので、確認してみます。

```shell
sh-4.2# strings /usr/lib64/libstdc++.so.6 | grep -e CXXABI
CXXABI_1.3
CXXABI_1.3.1
CXXABI_1.3.2
CXXABI_1.3.3
CXXABI_1.3.4
CXXABI_1.3.5
CXXABI_1.3.6
CXXABI_1.3.7
CXXABI_TM_1
```
確かに無いです。

#### GCCを最新化

[こちらのページ](http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/)から最新のGCCライブラリを探します。
今回はgcc-12.1.0をダウンロードします。

```shell
sh-4.2#  cd /opt
sh-4.2#  curl -LO http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-12.1.0/gcc-12.1.0.tar.gz
sh-4.2#  curl -LO http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-12.1.0/sha512.sum
```

チェックサムしてダウンロードに問題ないことを確認します。

```shell
sh-4.2# sha512sum --check sha512.sum
gcc-12.1.0.tar.gz: OK
```

ダウンロードしたファイルを解凍し、インストールしていきます。

```shell
sh-4.2# tar xzfv gcc-12.1.0.tar.gz -C /usr/local/src
sh-4.2# cd /usr/local/src/gcc-12.1.0/
sh-4.2# ./contrib/download_prerequisites
```

```shell
sh-4.2# ./contrib/download_prerequisites

# ・・・

isl-0.24.tar.bz2: OK
./contrib/download_prerequisites: line 261: bzip2: command not found
tar: This does not look like a tar archive
tar: Exiting with failure status due to previous errors
error: Cannot extract package from gmp-6.2.1.tar.bz2
```

download_prerequisitesの実行が上手くいきませんでした。
bzip2コマンドが必要のようです。

##### bzip2をインストール
bzip2をインストールします。

```shell
sh-4.2# yum install -y bzip2
```

#### GCCを最新化（続き）

download_prerequisitesを再実行すると上手くいきました。

```shell
sh-4.2# ./contrib/download_prerequisites
./contrib/download_prerequisites: line 49: type: wget: not found
gmp-6.2.1.tar.bz2: OK
mpfr-4.1.0.tar.bz2: OK
mpc-1.2.1.tar.gz: OK
isl-0.24.tar.bz2: OK
All prerequisites downloaded successfully.
```

```shell
sh-4.2# mkdir build
sh-4.2# cd build
sh-4.2# ../configure --enable-languages=c,c++ --prefix=/usr/local --disable-bootstrap --disable-multilib
```

```shell
sh-4.2# ../configure --enable-languages=c,c++ --prefix=/usr/local --disable-bootstrap --disable-multilib

# ・・・

checking for cl.exe... no
configure: error: in `/usr/local/src/gcc-12.1.0/build':
configure: error: no acceptable C compiler found in $PATH
See `config.log' for more details
```

configureの実行が上手くいきませんでした。
Cコンパイラがないようです。

##### Cコンパイラをインストール
Cコンパイラをインストールします。

```shell
sh-4.2# yum install -y gcc-c++
```

#### GCCを最新化（続き）

configureを再実行すると上手くいきました。

```shell
sh-4.2# ../configure --enable-languages=c,c++ --prefix=/usr/local --disable-bootstrap --disable-multilib

# ・・・

checking whether to enable maintainer-specific portions of Makefiles... no
configure: creating ./config.status
config.status: creating Makefile
```

続いてmake、及びmake installを実行します。
※makeは数時間レベルで時間が必要になります。

```shell
sh-4.2# make
sh-4.2# make install
```

バージョンを確認できればGCCのインストール成功です。

```shell
sh-4.2# gcc --version
gcc (GCC) 12.1.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```

あとは共有ライブラリの参照設定を変更します。

```shell
sh-4.2# cd /etc/ld.so.conf.d
sh-4.2# echo /usr/local/lib64 >> usr_local_lib64.conf
sh-4.2# mv /usr/local/lib64/libstdc++.so.6.0.30-gdb.py  /usr/local/lib64/back_libstdc++.so.6.0.30-gdb.py
sh-4.2# ldconfig
```

### 依存関係をインストールして実行（成功）
再度実行すると、今度は無事立ち上がりました。

```shell
sh-4.2# cd /opt/screwdriver/
sh-4.2# npm install && npm run start

# ・・・

Run `npm audit` for details.

> screwdriver-api@4.1.0 start
> ./bin/server
```

## storeリポジトリ
### 依存関係をインストールして実行
storeに移動して依存関係をインストールして実行します。

```shell
sh-4.2# cd /opt/store/
sh-4.2# npm install && npm run start

# ・・・

Run `npm audit` for details.

> screwdriver-store@4.0.0 start
> ./bin/server

{"level":"info","message":"Server running at http://localhost","timestamp":"2022-05-19T14:36:37.275Z"}
```

こちらは無事立ち上がりました。
ただ、それぞれフォアグラウンド実行だったので、バックグラウンドで実行します。

```shell
sh-4.2# cd /opt/ui/
sh-4.2# npm install && nohup npm run start &
```

```shell
sh-4.2# cd /opt/screwdriver/
sh-4.2# npm install && nohup npm run start &
```

```shell
sh-4.2# cd /opt/store/
sh-4.2# npm install && nohup npm run start &
```

## Screwdriverにアクセス
自端末側のブラウザで「[http://sd.screwdriver.cd:4200](http://sd.screwdriver.cd:4200)」にアクセス出来れば成功です。
サインインのボタンが表示されるので、認証を進めるとパイプラインの画面が表示されます。

# 参考文献

https://docs.screwdriver.cd/ja/about/contributing/getting-started-developing#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E7%92%B0%E5%A2%83%E3%81%AB%E6%A7%8B%E7%AF%89

https://docs.screwdriver.cd/about/contributing/getting-started-developing

https://hub.docker.com/_/centos

https://git-scm.com/book/ja/v2/%E4%BD%BF%E3%81%84%E5%A7%8B%E3%82%81%E3%82%8B-Git%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB

https://www.sejuku.net/blog/72545