Catapultノード ラズパイ用DockerImageビルド（ｖ1.0.3.6）

この記事ではラズパイ４用にCatapultノード（Symbol）を実行するためのDockerImageをビルドする方法を紹介します。

（所々、コマンドで作成されるアーキテクチャ指定がaarch64になっていない箇所がありますが、手動で書き換えれば問題ないのでそのまま進めます）

作業時間の目安：約3時間

# 事前準備

※作業は全てラズパイ上で行います。OSはUbuntuをインストールしてDockerが使えることが前提です。

**Symbolリポジトリのクローン**

```bash
git clone https://github.com/symbol/symbol.git
cd symbol
git checkout -b 1.0.3.6  refs/tags/client/catapult/v1.0.3.6
```

**中間イメージを作成する際に使用するコンフィグの作成**

```vi jenkins/catapult/configurations/gcc-12-aarch64.yaml```

```yaml
compiler: ../compilers/gcc-latest.yaml
architecture: armv8-a
```

# 手順１

Dockerfile-ubuntu-gcc-12を作成

```
vi jenkins/catapult/compilers/ubuntu-gcc/Dockerfile-ubuntu-gcc-12
```

https://github.com/symbol/symbol/blob/dev/jenkins/catapult/compilers/ubuntu-gcc/Dockerfile

```dockerfile
FROM arm64v8/ubuntu:22.04

ARG DEBIAN_FRONTEND=noninteractive

RUN apt-get update >/dev/null && \
    apt-get install -y \
    apt-utils \
    build-essential \
    gnupg2 \
    curl \
    xz-utils \
    wget \
    >/dev/null 
	
# Use the latest gcc version.
ARG COMPILER_VERSION=12
RUN apt-get update >/dev/null && \
    apt-get install -y \
    gcc-${COMPILER_VERSION} g++-${COMPILER_VERSION} >/dev/null && \
    update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${COMPILER_VERSION} 100 && \
    update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${COMPILER_VERSION} 100 && \
    update-alternatives --install /usr/bin/cc cc /usr/bin/gcc 100 && \
    update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++ 100 && \
    update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-${COMPILER_VERSION} 100 && \
    update-alternatives --install /usr/bin/gcov-dump gcov-dump /usr/bin/gcov-dump-${COMPILER_VERSION} 100 && \
    update-alternatives --install /usr/bin/gcov-tool gcov-tool /usr/bin/gcov-tool-${COMPILER_VERSION} 100 && \
    rm -rf /var/lib/apt/lists/*
```

**Docker Imageの作成**

```bash
docker build -f jenkins/catapult/compilers/ubuntu-gcc/Dockerfile-ubuntu-gcc-12 -t ishidad2/symbol-server-compiler:ubuntu-gcc-12 .
```

```debconf: delaying package configuration, since apt-utils is not installed```
※もし、上記のエラーが出た場合はとりあえず無視してOK

https://kaki-note-02.netlify.app/2020/06/20/

# 手順２


**jenkins/catapult/runDockerBuild.pyを修正**

※ishidad2はご自身の環境に合わせてください。

```diff
- return f'symbolplatform/symbol-server-build-base:{"-".join(name_parts)}'
+ return f'ishidad2/symbol-server-build-base:{"-".join(name_parts)}'

- image_name = f'symbolplatform/symbol-server-test-base:{self.operating_system}'
+ image_name = f'ishidad2/symbol-server-test-base:{self.operating_system}'

- '--source-path=/catapult-src/client/catapult',
+ '--source-path=/catapult-src/catapult',

- destination_image_name = f'symbolplatform/{destination_repository}:{destination_image_label}'
+ destination_image_name = f'ishidad2/symbol-server:{destination_image_label}'

- f'registry.hub.docker.com/{prepare_replacements["base_image_name"]}',
+ f'{prepare_replacements["base_image_name"]}',

- environment_manager.copy_tree_with_symlinks(source_path / 'client/catapult' / folder_name, folder_name)
+ environment_manager.copy_tree_with_symlinks(source_path / 'catapult' / folder_name, folder_name)
```

# 手順３

**jenkins/catapult/environment.pyの修正**

```diff
- for descriptor in [('ubuntu', '/usr/lib/x86_64-linux-gnu'), ('fedora', '/usr/lib64')]:
+ for descriptor in [('ubuntu', '/usr/lib/aarch64-linux-gnu'), ('fedora', '/usr/lib64')]:
```

# 手順４

**cmakeと様々なシステムパーッケージを含む最初の中間イメージを作る**

```bash
python3 ./jenkins/catapult/baseImageDockerfileGenerator.py \
    --compiler-configuration jenkins/catapult/configurations/gcc-12-aarch64.yaml \
    --operating-system ubuntu \
    --versions ./jenkins/catapult/versions.properties \
    --layer os \
    > Dockerfile-preimage1
```

FROMとcmakeのアーキテクチャ（x86_64となっている部分を全てaarch64にする）を変更してDockerfile-preimage1として保存

```dockerfile
FROM ishidad2/symbol-server-compiler:ubuntu-gcc-12
ARG DEBIAN_FRONTEND=noninteractive
LABEL maintainer="Catapult Development Team"
RUN apt-get -y update \
    && apt-get install -y autoconf ca-certificates ccache curl gdb git libatomic-ops-dev libgflags-dev libsnappy-dev libtool make ninja-build pkg-config python3 python3-ply xz-utils \
    && rm -rf /var/lib/apt/lists/* \
    && curl -o cmake-3.26.0-Linux-aarch64.sh -SL "https://github.com/Kitware/CMake/releases/download/v3.26.0/cmake-3.26.0-Linux-aarch64.sh" \
    && chmod +x cmake-3.26.0-Linux-aarch64.sh \
    && ./cmake-3.26.0-Linux-aarch64.sh --skip-license --prefix=/usr \
    && rm -rf cmake-3.26.0-Linux-aarch64.sh
```

以下コマンドを実行

```
docker build -f Dockerfile-preimage1 -t ishidad2/symbol-server-build-base:ubuntu-gcc-12-armv8-a-preimage1 .
```

# 手順５

**boostビルドを含む2つ目の中間イメージを作成**

```bash
python3 ./jenkins/catapult/baseImageDockerfileGenerator.py \
    --compiler-configuration jenkins/catapult/configurations/gcc-12-aarch64.yaml \
    --operating-system ubuntu \
    --versions ./jenkins/catapult/versions.properties \
    --layer boost \
    > Dockerfile-preimage2
```

FROMを変更してDockerfile-preimage2として保存

```dockerfile
FROM ishidad2/symbol-server-build-base:ubuntu-gcc-12-armv8-a-preimage1
RUN curl -o /usr/local/bin/gosu -SL "https://github.com/tianon/gosu/releases/download/1.14/gosu-$(dpkg --print-architecture)" \
    && chmod +x /usr/local/bin/gosu
RUN curl -o boost_1_80_0.tar.gz -SL https://boostorg.jfrog.io/artifactory/main/release/1.80.0/source/boost_1_80_0.tar.gz \
    && tar -xzf boost_1_80_0.tar.gz \
    && mkdir /mybuild \
    && cd boost_1_80_0 \
    && ./bootstrap.sh  --prefix=/mybuild \
    && ./b2 address-model=64 runtime-link=shared threading=multi link=shared --layout=system variant=release cxxflags='-march=armv8-a' --prefix=/mybuild --without-context --without-contract --without-coroutine --without-fiber --without-graph --without-graph_parallel --without-headers --without-iostreams --without-json --without-mpi --without-nowide --without-python --without-serialization --without-stacktrace --without-test --without-timer --without-type_erasure --without-wave -j 8 stage release \
    && ./b2 address-model=64 runtime-link=shared threading=multi link=shared --layout=system variant=release cxxflags='-march=armv8-a' --without-context --without-contract --without-coroutine --without-fiber --without-graph --without-graph_parallel --without-headers --without-iostreams --without-json --without-mpi --without-nowide --without-python --without-serialization --without-stacktrace --without-test --without-timer --without-type_erasure --without-wave install
```

以下コマンドを実行

```bash
docker build -f Dockerfile-preimage2 -t ishidad2/symbol-server-build-base:ubuntu-gcc-12-armv8-a-preimage2 .
```

# 手順６

**その他すべての依存ツール(mongo + mongo-cxx, libzmq + cppzmq, rocksdb)を含む第3の中間イメージ作成**

```bash
python3 ./jenkins/catapult/baseImageDockerfileGenerator.py \
    --compiler-configuration jenkins/catapult/configurations/gcc-12-aarch64.yaml \
    --operating-system ubuntu \
    --versions ./jenkins/catapult/versions.properties \
    --layer deps \
    > Dockerfile-preimage3
```

FROMとopensslのConfigureをaarch64に変更してDockerfile-preimage3として保存
※テストを無効にするために-DENABLE_TESTS=OFFを追記

```dockerfile
FROM ishidad2/symbol-server-build-base:ubuntu-gcc-12-armv8-a-preimage2
RUN git clone https://github.com/openssl/openssl.git -b openssl-3.1.0 \
    && cd openssl \
    && CFLAGS='-march=armv8-a' perl ./Configure linux-aarch64  --prefix=/usr/catapult/deps --openssldir=/usr/catapult/deps --libdir=/usr/catapult/deps \
    && make -j 8 \
    && make install \
    && cd .. \
    && rm -rf openssl
RUN git clone https://github.com/mongodb/mongo-c-driver.git -b 1.23.2 \
    && cd mongo-c-driver \
    && mkdir _build \
    && cd _build \
    && cmake -DOPENSSL_ROOT_DIR=/usr/catapult/deps -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DENABLE_MONGODB_AWS_AUTH=OFF -DENABLE_TESTS=OFF -DENABLE_EXAMPLES=OFF -DENABLE_SASL=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_CXX_FLAGS='-march=armv8-a' .. \
    && make -j 8 \
    && make install \
    && cd .. \
    && rm -rf mongo-c-driver \
    && echo "force rebuild revision 1"
RUN git clone https://github.com/mongodb/mongo-cxx-driver.git -b r3.7.1 \
    && cd mongo-cxx-driver \
    && mkdir _build \
    && cd _build \
    && cmake -DENABLE_TESTS=OFF -DOPENSSL_ROOT_DIR=/usr/catapult/deps -DCMAKE_CXX_STANDARD=17 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_CXX_FLAGS='-march=armv8-a' .. \
    && make -j 8 \
    && make install \
    && cd .. \
    && rm -rf mongo-cxx-driver \
    && echo "force rebuild revision 1"
RUN git clone https://github.com/zeromq/libzmq.git -b v4.3.4 \
    && cd libzmq \
    && mkdir _build \
    && cd _build \
    && cmake -DENABLE_TESTS=OFF -DWITH_TLS=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_CXX_FLAGS='-march=armv8-a' .. \
    && make -j 8 \
    && make install \
    && cd .. \
    && rm -rf libzmq \
    && echo "force rebuild revision 1"
RUN git clone https://github.com/zeromq/cppzmq.git -b v4.9.0 \
    && cd cppzmq \
    && mkdir _build \
    && cd _build \
    && cmake -DCPPZMQ_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_CXX_FLAGS='-march=armv8-a' .. \
    && make -j 8 \
    && make install \
    && cd .. \
    && rm -rf cppzmq \
    && echo "force rebuild revision 1"
RUN git clone https://github.com/facebook/rocksdb.git -b v7.10.2 \
    && cd rocksdb \
    && mkdir _build \
    && cd _build \
    && cmake -DENABLE_TESTS=OFF -DPORTABLE=1 -DWITH_TESTS=OFF -DWITH_TOOLS=OFF -DWITH_BENCHMARK_TOOLS=OFF -DWITH_CORE_TOOLS=OFF -DWITH_GFLAGS=OFF -DUSE_RTTI=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_CXX_FLAGS='-Wno-error=maybe-uninitialized -march=armv8-a' .. \
    && make -j 8 \
    && make install \
    && cd .. \
    && rm -rf rocksdb \
    && echo "force rebuild revision 1"
```

以下コマンドを実行

```bash
docker build -f Dockerfile-preimage3 -t ishidad2/symbol-server-build-base:ubuntu-gcc-12-armv8-a-preimage3 . --memory-swap -1
```

# 手順７

**最終レイヤー作成**

```bash
python3 ./jenkins/catapult/baseImageDockerfileGenerator.py \
    --compiler-configuration jenkins/catapult/configurations/gcc-12-aarch64.yaml \
    --operating-system ubuntu \
    --versions ./jenkins/catapult/versions.properties \
    --layer test \
    > Dockerfile-preimage4
```

FROMとopensslのアーキテクチャの指定をaarch64に変更してDockerfile-preimage4として保存

```dockerfile
FROM ishidad2/symbol-server-build-base:ubuntu-gcc-12-armv8-a-preimage3
RUN git clone https://github.com/google/googletest.git -b release-1.12.1 \
    && cd googletest \
    && mkdir _build \
    && cd _build \
    && cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DBUILD_GMOCK=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_CXX_FLAGS='-march=armv8-a' .. \
    && make -j 8 \
    && make install \
    && cd .. \
    && rm -rf googletest \
    && echo "force rebuild revision 1"
RUN git clone https://github.com/google/benchmark.git -b v1.7.0 \
    && cd benchmark \
    && mkdir _build \
    && cd _build \
    && cmake -DBENCHMARK_ENABLE_GTEST_TESTS=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_CXX_FLAGS='-march=armv8-a' .. \
    && make -j 8 \
    && make install \
    && cd .. \
    && rm -rf benchmark \
    && echo "force rebuild revision 1"
RUN apt-get -y update \
    && apt-get remove -y --purge pylint \
    && apt-get install -y python3-pip lcov libssl-dev \
    && python3 -m pip install -U pycodestyle pylint pyyaml
RUN git clone https://github.com/openssl/openssl.git -b openssl-3.0.7 \
    && cd openssl \
    && CFLAGS='-march=armv8-a' perl ./Configure linux-aarch64 --prefix=/usr/catapult/deps --openssldir=/usr/catapult/deps --libdir=/usr/catapult/deps \
    && make -j 8 \
    && make install \
    && cd .. \
    && rm -rf openssl
RUN echo "docker image build $BUILD_NUMBER"
CMD ["/bin/bash"]

```


以下コマンドを実行して最終イメージを作成

```bash
docker build -f Dockerfile-preimage4 -t ishidad2/symbol-server-build-base:ubuntu-gcc-12-armv8-a .
```

# 手順８

**symbol-server-test-baseイメージを作成**

以下をDocker-test-preimageとして保存
※前回とはベースのイメージのバージョンが異なります。古いイメージを使うと最終的にライブラリエラーになりますので、必ずバージョンを22.04へ上げて再ビルドしてください。

※prefのコンパイルに失敗するので変数を追加

```dockerfile
FROM arm64v8/ubuntu:22.04

CMD ["/bin/bash"]
ARG DEBIAN_FRONTEND=noninteractive
ARG NO_LIBTRACEEVENT=1

RUN apt-get -y update \
    && apt-get install -y bison gdb git flex python3 python3-ply python3-pip shellcheck inotify-tools libdw-dev libelf-dev libiberty-dev libslang2-dev \
       libunwind-dev libssl-dev libperl-dev libzstd-dev libcap-dev libnuma-dev libbabeltrace-dev libpfm4-dev libtraceevent-dev \
    && rm -rf /var/lib/apt/lists/* \
    && pip3 install -U colorama cryptography gitpython pycodestyle pylint pylint-quotes PyYAML \
    && git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git linux.git \
    && cd linux.git/tools/perf \
    && make \
    && cp perf /usr/bin \
    && cd ../../.. \
    && rm -rf linux.git
```

以下を実行

```bash
docker build -f Docker-test-preimage -t ishidad2/symbol-server-test-base:ubuntu .
```


以上でクライアントのコンパイルをする準備が出来ました。

# 手順９

**クライアントのコンパイル**

下記のコマンドを実行するとこれまで作成したDockerイメージを使用したコンパイルが実行されます。

```bash
python3 jenkins/catapult/runDockerBuild.py \
--compiler-configuration jenkins/catapult/configurations/gcc-12-aarch64.yaml \
--build-configuration jenkins/catapult/configurations/release-private.yaml \
--operating-system ubuntu \
--user "$(id -u):$(id -g)" \
--source-path client \
--destination-image-label gcc-12-armv8-a-main-9273d6c5
```

正常にここまで終わると以下のようにイメージが作成されていると思います。

![スクリーンショット 2023-08-28 20.34.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934471/85b0e931-a404-d945-aa8d-8a59b899aa60.png)


# tagを変更
※destination-image-labelの指定を直接gcc-1.0.3.6にしてもOKです。

```bash
docker tag ishidad2/symbol-server:gcc-12-armv8-a-main-9273d6c5 ishidad2/symbol-server:gcc-1.0.3.6
```

以上でv1.0.3.6のイメージ作成を終わります。

今回ビルドしたImageは以下のDockerhubで公開しています。

https://hub.docker.com/layers/ishidad2/symbol-server/gcc-1.0.3.6/images/sha256-f721ebb57954831b620236657f6aa84fdbac9ca54aec9f797ac8e59dfa6911dc?context=repo


# rest(v2.4.3)のDockerImageをビルド

続いてRestもバージョンが上がっていたのでビルドを行います。

**gitからrest v2.4.3のタグをチェックアウト**

```bash
git checkout -b rest/v2.4.3 refs/tags/rest/v2.4.3
```

client/restフォルダへ移動して以下コマンドでrestイメージを作成

```bash
docker build -f Dockerfile -t ishidad2/symbol-rest:2.4.3 .
```

https://hub.docker.com/layers/ishidad2/symbol-rest/2.4.3/images/sha256-8b44a1930e2a9874c56c3fa72efb491c02cde1202826f1e82c183bbe0e7822dd?context=repo


使い方は下記を参照してください。

https://qiita.com/ishidad2/items/642a8b64c6143b1c7927#%E3%82%B3%E3%83%B3%E3%83%95%E3%82%A3%E3%82%B0%E3%81%AE%E4%BD%9C%E6%88%90

# 補足

現在のbootstrapでコンフィグを作成するとmongodbのイメージのバージョンが「mongo:5.0.15」で作成されますが、このバージョンのDockerイメージではラズパイはサポートされていませんので、以下のようにカスタムプリセットを用いて古いバージョンに書き換える必要があります。

```
symbolServerImage: 'ishidad2/symbol-server:gcc-1.0.3.6'
symbolRestImage: 'ishidad2/symbol-rest:2.4.3'
mongoImage: 'mongo:4.4.3-bionic'
```

# 最後に

ここまで書いて衝撃的な事実を見つけてしまいました。。。

https://hub.docker.com/layers/symbolplatform/symbol-server/gcc-latest-1.0.3.6-arm64/images/sha256-4652e230affe9f2052ee532a5a478650ddd0ef42fd45ec1e0f5a615e8f33819c?context=explore

公式のARM64イメージあるやんけー( ´Д`)y━･~~

おしまい。