Apptainerで任意のアプリやR packageを追加したコンテナをApple silicon Macで作成する

## 動機について
機密情報を扱った解析を行うため、internetから隔絶されたclosedなAmazon Working Spacesに構築されたバーチャルデスクトップにアクセスすることになりました。必要最低限のソフトウェアが導入されていたものの、過去に開発したRのpackage [MicroSEC](https://github.com/MANO-B/MicroSEC)を使用するためには[Apptainer](https://apptainer.org)のコンテナにした上で管理者にチェックを受け使用可能にしてもらう必要がありました。

Dockerに関する情報はinternetに多数ありますが、Apptainerについての情報、とくに具体的なsifファイルの作成までの過程についての情報が不足していたため、ここに記録として残しておくことにしました(2024年6月時点の情報です)。

## Apptainerについて
[Apptainerは以前Singularityと呼ばれていた](https://sc.ddbj.nig.ac.jp/software/Apptainer/)、Dockerの様なコンテナ化ソフトです。ユーザー権限で実施可能なこと、コンテナが書き込み禁止に設定されることからセキュリティ対策が行いやすい点で有利とされています。一般的な使用法としては、[dockerhub](https://hub.docker.com)に登録されている（または自分で登録した）コンテナイメージを基にして、追加でインストールするアプリケーションやパッケージをdefinition fileで指定した上でApptainerコンテナに変換するという流れになります。

## Apple siliconでのApptainerの実行について
Amazon Working SpacesではAmazon linuxがx86_64アーキテクチャで動作していること、Apptainerが基本的にはlinux上で動作すること、Apple siliconがArmアーキテクチャであることから多少の工夫が必要になりました。ubuntuで実行する方がステップとしてはすくないのですが出張中にmacbookで作業したかったため試してみることにしました。cleanなUbuntu環境を用いることになるため環境依存性がないことは利点と思います。

## 具体的なコマンド
- Apple silicon macにlimaを導入する
Apple silicon上でx86_64アーキテクチャで構築されたubuntuのdockerコンテナを動作させるために、[limaとdockerをインストール](https://blog.amedama.jp/entry/lima-macos-amd64-vm)しました([参考](https://qiita.com/mm_sys/items/28a0217256b56918fee4))。
準備として[docker desktop](https://docs.docker.com/desktop/install/mac-install/)、[homebrew](https://brew.sh/ja/)および[Rosetta2](https://support.apple.com/ja-jp/102527)のインストールを済ませておく必要があります。
```
# lima, x64_86 emulator qemu, docker CLIのインストール
brew install qemu lima docker

# .zshrc の末尾に eval "$(limactl completion zsh)" を追記
# 
echo 'eval "$(limactl completion zsh)"' >> ~/.zshrc

```
- limaにApptainerコンテナを導入する
limaでのubuntu virtual machineの作成については以下のサイトで非常にわかりやすくまとめられています [(1)](https://qiita.com/yteraoka/items/0d793d06cddccad73b0b), [(2)](https://zenn.dev/belltailjp/articles/2024-mac-lima-x86)。また、lima上でapptainerが動作するubuntu virtual machineの起動方法については[Apptainer公式サイト](https://apptainer.org/docs/admin/main/installation.html)に記載があります。これらの情報に基づいてインストールを進めました。
- yamlファイルの作成
apptainer公式サイトから推奨されている、apptainerが動作するubuntu24.04 virtual machineが作成可能な[yamlファイルの例](https://github.com/lima-vm/lima/blob/master/examples/apptainer-rootful.yaml)がありますが、権限の関係かapptainerのインストールが上手くいきませんでした(sudoを追記すれば動く気がします)。また、このまま使用するとarmアーキテクチャのvirtual machineが構築されてしまうこと、CPU数やメモリの指定が必要であることなど問題があり、対応として[以下の項目を変更](https://qiita.com/mm_sys/items/28a0217256b56918fee4)しました。[高速なRosettaを使うのか低速なQEMUを使用するのか](https://lima-vm.io/docs/config/multi-arch/)は実行する用途にもよりますが、以下ではdocker hubのx86_64アーキテクチャのコンテナイメージを使用するためやむを得ず低速なQEMUを使用しています。環境に応じて数値など変更が必要です。
```
# x86_64アーキテクチャを指定
arch: "x86_64"

# CPU, memory, storageを指定
cpus: 4
memory: "16GiB"
disk: "100GiB"

# マウントするディレクトリの指定
mounts:
- location: "~"
  writable: false
- location: "~/apptainer_work"
  writable: true
- location: "/tmp/lima"
  writable: true
```
最終的に使用したのは、以下をapptainer.yamlとして保存したものです。
```
arch: "x86_64"
cpus: 4
memory: "16GiB"
disk: "100GiB"
mounts:
- location: "~"
  writable: false
- location: "/tmp/lima"
  writable: true
images:
- location: "https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img"
  arch: "x86_64"
containerd:
  system: false
  user: false
```
書式に間違いがないかを確認します。
```
$ limactl validate apptainer.yaml
```
- lima上で動作する、ApptainerがインストールされたUbuntu virtual machineの構築
上記で作成したyamlファイルを用いてvirtual machineを構築します。
```
$ limactl start ./apptainer.yaml
? Creating an instance "apptainer" Proceed with the current configuration
INFO[0001] Starting the instance "apptainer" with VM driver "qemu" 
INFO[0001] Attempting to download the image              arch=x86_64 digest="sha256:32a9d30d18803da72f5936cf2b7b9efcb4d0bb63c67933f17e3bdfd1751de3f3" location="https://cloud-images.ubuntu.com/releases/24.04/release-20240423/ubuntu-24.04-server-cloudimg-amd64.img"
...
INFO[0156] READY. Run `limactl shell apptainer` to open the shell.
```
起動したubuntu virtual machineのシェルを立ち上げます。
```
limactl shell apptainer
```
x86_64アーキテクチャで動作していることを確認します。
```
$ uname -m
x86_64
$ uname -sr
Linux 6.8.0-31-generic
$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 24.04 LTS
Release:	24.04
Codename:	noble
$ free -h
               total        used        free      shared  buff/cache   available
Mem:            15Gi       506Mi        14Gi       5.0Mi       594Mi        15Gi
Swap:             0B          0B          0B
```
apptainerのインストールを進めます。
```
$ sudo add-apt-repository -y ppa:apptainer/ppa
$ sudo apt-get update
$ sudo apt-get install -y apptainer
```
Apple siliconのMacのlima上でx86_64アーキテクチャで動作するubuntuでapptainerが使用可能となりました。以後は/tmp/limaで作業を行います。
```
$ cd /tmp/lima
$ apptainer
Usage:
  apptainer [global options...] <command>

Available Commands:
...

$ apptainer pull docker://ghcr.io/apptainer/lolcow
INFO:    Converting OCI blobs to SIF format
INFO:    Starting build...
...

$ sudo apptainer run lolcow_latest.sif
 _____________________________
< Fri Jun 7 20:25:17 JST 2024 >
 -----------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
```
ここからは目的のR packageの動作に必要なsamtoolsのインストールおよび依存しているR packageのインストールを記載したdefinition fileの記載に移ります。書式についていくつか参考になるページがありました。[(1)](https://apptainer.org/docs/user/main/build_a_container.html), [(2)](https://sciwiki.fredhutch.org/compdemos/Apptainer/)

以下の内容をMicroSEC.defとして保存しました。
```
BootStrap: docker
From: rocker/r-base:4.2.3

%post
    cd /tmp
    apt-get -y update
    apt-get install -y build-essential curl cmake perl libncurses-dev libbz2-dev liblzma-dev tar wget bzip2 gcc zlib1g-dev make libxml2-dev libcurl4-openssl-dev postgresql libpq-dev libmariadb-dev-compat libmariadb-dev libfontconfig1-dev libnode-dev libssl-dev libharfbuzz-dev libfribidi-dev libfreetype-dev libpng-dev libtiff5-dev libjpeg-dev libclang-dev gdebi-core cargo libudunits2-dev libmagick++-dev texlive texlive-lang-japanese evince xdvik-ja libpoppler-cpp-dev xorg libx11-dev libglu1-mesa-dev gdal-bin libgdal-dev
    wget https://raw.githubusercontent.com/MANO-B/MicroSEC/main/MicroSEC.R
    wget https://github.com/samtools/samtools/releases/download/1.12/samtools-1.12.tar.bz2
    tar xvjf samtools-1.12.tar.bz2  --no-same-owner
    cd samtools-1.12/
    ./configure
    make
    make install
    cd ..
    rm samtools-1.12.tar.bz2
    R --no-echo -e 'install.packages("https://cran.r-project.org/src/contrib/Archive/Matrix/Matrix_1.5-3.tar.gz", repos=NULL, type="source")'
    R --no-echo -e 'install.packages("https://cran.r-project.org/src/contrib/Archive/MatrixModels/MatrixModels_0.5-1.tar.gz", repos=NULL, type="source")'
    R --no-echo -e 'install.packages(c("knitr", "askpass", "credentials", "rmarkdown", "httr", "gh", "WikipediR", "roxygen2", "usethis", "pkgdown", "rcmdcheck", "rversions", "urlchecker", "quantreg", "gert", "rmarkdown", "zip", "credentials", "spelling","mnormt", "rentrez", "XML", "numDeriv", "jsonlite", "RCurl", "ggplot2", "tidyverse", "RColorBrewer", "survival", "WriteXLS", "readr"), dependencies = TRUE, repos="https://cloud.r-project.org/")'
    R --no-echo -e 'install.packages(c("tidyr", "openxlsx", "data.table", "R.utils", "stringr", "magrittr", "dplyr", "gtools", "devtools", "BiocManager", "V8", "juicyjuice"), dependencies = TRUE, repos="https://cloud.r-project.org/")'
    R --no-echo -e 'install.packages("devtools", dependencies = TRUE, repos="https://cloud.r-project.org/")'
    R --no-echo -e 'BiocManager::install(c("BiocVersion", "Rhtslib", "ComplexHeatmap", "BiocStyle", "Rsamtools", "GenomeInfoDb", "GenomicRanges", "Biostrings", "GenomicAlignments", "SummarizedExperiment", "rtracklayer"), update=FALSE)'
    R --no-echo -e 'BiocManager::install("BSgenome.Hsapiens.UCSC.hg38", update=FALSE)'
    R --no-echo -e 'devtools::install_github("MANO-B/MicroSEC", upgrade="never")'

%environment
export PATH=/usr/local/bin:$PATH
export LC_ALL=C.UTF-8

```
以下のコマンドでdefinition fileを基にしてapptainerコンテナを作成します。
```
$ sudo apptainer build MicroSEC.sif MicroSEC.def
...
INFO:    Adding environment to container
INFO:    Creating SIF file...
INFO:    Build complete: MicroSEC.sif
```
QEMUでx86_64をエミュレートするため動作が非常に遅く、ダウンロードやsamtoolsのコンパイルなどで時間を要します。実機の5-10倍遅い印象です。

作成したsifファイルを実行してみます。
```
# bash consoleの実行
$ sudo apptainer exec MicroSEC.sif bash

# パッケージがインスリンされたRの実行
$ sudo apptainer exec MicroSEC.sif R

# 目的のMicroSECを用いた解析の実行
sudo apptainer exec MicroSEC.sif Rscript /MicroSEC.R /tmp/lima/MicroSEC_test_data /tmp/lima/MicroSEC_test_data/Sample_list.txt Y
```
proxy環境だと場合により設定の追加が必要なこともあるかもしれません。