Ubuntuサーバの構築 + Dockerを用いたGPU開発環境の構築【2023年12月 / 2024年1月 追記】

ここ最近，研究室内のサーバを構築する機会が多く，毎回のように検索をしているので，いい加減にまとめておこうと考えた次第です．（近々，もう何台か組み立てる予定もあるので……）
研究室に入って2年目の学部生がメモとして書いている記事ですので，間違い等が有りましたらお手柔らかにお願いします．

# 環境
いくつもあるサーバの個々の構成についてはすべて書くことはしないつもりですが，特に環境構築に関係すると思われる部分を表にまとめておきます．

|項目|説明|
|:---:|:---|
|OS|Ubuntu 22.04 LTS|
|GPU|NVIDIA製(GeForce)|
|利用目的|研究目的の深層学習|
|その他|ssh接続，Docker環境，研究室内でのみの利用|

では，早速！（なお，サーバは組み上げ済みとします．）

# インストールメディアの作成
ここでメディアを作成するPCはWindowsを使用しています．
インストールメディアを作成するために必要なものを下の表に示します．

|項目|一言説明|補足事項|
|:-:|:-|:-|
|USBメモリ|インストールメディアとして利用|12GiB以上推奨，何も保存されていないことを確認|
|isoファイル|Ubuntuのもと|https://jp.ubuntu.com/download, LTSを選んでおくのが無難（と思います）|
|Rufus|フォーマットのためのソフトウェア|https://rufus.ie/ja/, 使い方はトップページに画像で説明されているので，非常に簡単！|

Rufusに関しては他のソフトウェアもあるようですが，触ったことが無いので分かりません．インストールメディアは1度作成してしまえば，それ以降作る機会もあまり無いので作れればそれで良いかなと考えています．

# インストール
先の工程で作成したインストールメディアをサーバに挿し，電源をON．基本的に表示される案内に従って操作を進めれば問題は無いかなと思います．（特に，先の工程でUbuntu Desktopを選んだ方は，マウスでポチポチしているだけで大丈夫なので，直感的に理解できると思います！）
一応，参考文献をいくつか．

https://kb.seeck.jp/archives/19354#toc5

https://www.kkaneko.jp/tools/ubuntu/ubuntudesktop.html


# sshの有効化
前提として，クライアント側（自分の端末）のssh接続の準備は整っているものとします．
もし，ssh接続を一度もしたことがない（気がする）方は以下辺りを参考にされてください．

- (Windows) 

https://learn.microsoft.com/ja-jp/windows-hardware/manufacture/desktop/factoryos/connect-using-ssh?view=windows-11#create-a-keypair

- (Mac) 

https://qiita.com/wakahara3/items/52094d476774f3a2f619

※挙げておいて何ですが，Macの方は試していないので，より良い記事があればご教示ください．

以下ではホスト側（サーバ側）での作業について説明します．

## OpenSSHサーバの確認
ターミナルで以下のコマンドを実行し，`Active: active (running)`と表示されている方は，[公開鍵認証](#公開鍵認証)まで進んでください．


```bash 
$ systemctl status sshd.service
```

ここでOpenSSHサーバが入っているかどうかは，インストールの際に選択した項目によって若干の違いがあるようです．

## OpenSSHサーバのインストール
ターミナル上で以下のコマンドを実行すると，OpenSSHのインストールが開始されます．

```bash
$ sudo apt update
$ sudo apt install openssh-server
```

## 公開鍵認証
ここでは公開鍵をホスト側に登録します．
ちなみに，Ubuntu Desktopを入れた方はGUIでも操作可能だったかと思いますが，私はCUIの方が慣れているため，そちらベースの話になります．ご了承ください．

先ず，ターミナル上で`/home/<username>/.ssh`にアクセスします．ここに`authorized_keys`がなければ作成しておいてください．

```bash
$ touch authorized_keys
```

次に，以下のようなコマンドで編集をおこないます．

```bash
$ sudo nano authorized_keys
```

ここに，クライアント側の公開鍵(id_rsa.pub)をコピペして保存しておいてください．

最後に，パーミッションの変更をおこないます．

```bash
$ chmod 600 authorized_keys
```

# Dockerのインストール
最初に記載している通り，Dockerを用いて環境構築をおこなうので，そのインストールをおこなっていきます．
とは言っても，非常に簡単で，[Docker docs](https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository)で丁寧に解説されています．
[そちら](https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository)を見ていただくのが一番なのですが，英語で説明されているので一応日本語にしてこちらにも掲載しておきます．

1. Dockerのaptリポジトリをセットアップする
    ```bash
    # Dockerの公式GPGキーを追加する：
    $ sudo apt-get update
    $ sudo apt-get install ca-certificates curl gnupg
    $ sudo install -m 0755 -d /etc/apt/keyrings
    $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    $ sudo chmod a+r /etc/apt/keyrings/docker.gpg
    
    # リポジトリをaptソースに追加する：
    $ echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
      $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    $ sudo apt-get update
    ```

2. Dockerパッケージのインストール
    ```bash
    $ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    ```
3. `hello-world`イメージを実行して，Docker Engineのインストールが成功したことを確認する
    ```bash
    $ sudo docker run hello-world
    ```

GPUを利用しない方はここで終了です！お疲れ様でした！
GPUを利用する方は更に頑張りましょう……

# GPUのためのツールのインストール
ここではNVIDIA製のGPUを前提として話していきます．それ以外のGPUは使ったことがないので分かりません．

また，最近（？）になって第3次AIブームが到来したからか，間違った内容の記事や古い情報を載せている記事がそれなりに散見されました．（この記事もその1つで無ければ良いのですが……）ある記事に従って作業を進めていたところOSが起動しなくなってしまったなんてことも有りました．
このことが本記事を書くことになったきっかけの1つでもあり，皆様のお力になれればと思います．

愚痴はこの程度にして，ここで扱う操作について簡単にまとめておきます．

1. `nvidia-driver`のインストール
1. `nvidia-container-runtime`のインストール

あれ，`CUDA`, `cuDNN`は？という方の為に先に言及しておきますと，以前に当研究室で利用していたサーバのローカル環境がこれらのパッケージの関係で壊れてしまい非常に面倒なことになりました．（メンテナンス時に発覚）
以降，ローカル環境を汚さないようにするためにDockerを用いているのですが，その場合は`CUDA`, `cuDNN`のインストールは必要ありません．

## nvidia-driverのインストール
先ず，以下のコマンドでドライバの一覧を取得します．

```bash
$ ubuntu-drivers devices
```

以下のような一覧が表示されると思います．（適当なそこら辺に転がっていたサーバで試しているので，GPUが古いのは勘弁してください．笑）

```bash
vendor   : NVIDIA Corporation
model    : TU104 [GeForce RTX 2080]
driver   : nvidia-driver-418-server - distro non-free
driver   : nvidia-driver-525 - distro non-free
driver   : nvidia-driver-535-server-open - distro non-free
driver   : nvidia-driver-535 - distro non-free recommended
driver   : nvidia-driver-525-server - distro non-free
driver   : nvidia-driver-525-open - distro non-free
driver   : nvidia-driver-470 - distro non-free
driver   : nvidia-driver-535-server - distro non-free
driver   : nvidia-driver-535-open - distro non-free
driver   : nvidia-driver-450-server - distro non-free
driver   : nvidia-driver-470-server - distro non-free
driver   : xserver-xorg-video-nouveau - distro free builtin
```

以上のリストから，1つ適切なものを選択し，以下のコマンドでインストールを実行してください．

```bash
$ sudo apt install nvidia-driver-***
```

基本的に`recommended`と書いてあるものを選択すれば問題ないと思いますが，`-server`や`-open`などがある場合は注意が必要です．（無印以外をインストールしたことでOSが立ち上がらなくなったことがあり，他の記事でもそのような報告を見かけました．参考まで．）
ちなみに，この記事を書く際に使用したサーバの環境(GeForce RTX 2080)では`nvidia-driver-535`で無事に動作しました．

最後に，動作確認をおこないます．以下のコマンドを実行してください．

```bash
$ nvidia-smi
```

以下のような出力が得られれば成功です．

```bash
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.129.03             Driver Version: 535.129.03   CUDA Version: 12.2     |
|-----------------------------------------+----------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |         Memory-Usage | GPU-Util  Compute M. |
|                                         |                      |               MIG M. |
|=========================================+======================+======================|
|   0  NVIDIA GeForce RTX 2080        Off | 00000000:01:00.0  On |                  N/A |
| 28%   52C    P8               4W / 215W |    300MiB /  8192MiB |      1%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+
                                                                                         
+---------------------------------------------------------------------------------------+
| Processes:                                                                            |
|  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
|        ID   ID                                                             Usage      |
|=======================================================================================|
|    0   N/A  N/A      2058      G   /usr/lib/xorg/Xorg                           64MiB |
|    0   N/A  N/A      2167    C+G   ...libexec/gnome-remote-desktop-daemon      112MiB |
|    0   N/A  N/A      2204      G   /usr/bin/gnome-shell                        118MiB |
+---------------------------------------------------------------------------------------+
```

これ以外の出力の場合はやり直しです……

### 2024年1月追記
下記のコマンドであれば，面倒な確認は必要なく，これだけでインストールが可能なようです．
ただ，エラーが出るという記事も（比較的）多く見受けられるので，ご自身で手間を天秤にかけてご判断下さい．

```bash 
$ sudo ubuntu-drivers autoinstall
```

## `nvidia-container-runtime`のインストール
以下のコマンドを順に実行するだけです．ここまで，対処できた人にとっては余裕でしょう．

```bash
$ curl -s -L https://nvidia.github.io/nvidia-container-runtime/gpgkey |   sudo apt-key add -
$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
$ curl -s -L https://nvidia.github.io/nvidia-container-runtime/$distribution/nvidia-container-runtime.list |   sudo tee /etc/apt/sources.list.d/nvidia-container-runtime.list
$ sudo apt update
$ sudo apt install nvidia-container-runtime
$ service docker restart
```

# 最後に
以上で，Dockerを用いる場合のGPU環境の準備が完了しました．お疲れ様でした！
後は好きなようにDocker環境を準備するだけです．

とは言っても，Dockerで環境構築をしたことが無いという方やGPUを用いた環境構築が分からないという方もいるかも知れないので，詳細な解説はしませんが（気分次第で別の記事でまとめるかも？）サンプルを貼っておきます．

```docker: docker-compose.yml
version: '3'

services:
  dev:
    build: .
    container_name: dev_con
    expose:
      - "8888"
    ports:
      - "127.0.0.1:8888:8888"
    entrypoint: jupyter lab --allow-root --ip=0.0.0.0 --port=8888 --no-browser --notebook-dir=/home/workdir
    volumes:
      - .:/home/workdir
    environment:
      - "NVIDIA_VISIBLE_DEVICES=all"
      - "NVIDIA_DRIVER_CAPABILITIES=all"
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia 
              capabilities:
              - gpu
```

```Dockerfile: Dockerfile
FROM ubuntu:22.04

WORKDIR /home/src

RUN apt update \
    && apt install -y \
    git \
    python3.10 

RUN update-alternatives --install /usr/bin/python python /usr/bin/python3.10 1 \
    && apt install -y python3-pip \
    && pip install -U pip \
    && pip install jupyterlab \
    pandas \
    tensorflow \
    torch \
    matplotlib \
    seaborn \
    scikit-learn
```

ちなみに，上の2つのファイルを同じ階層に置き，以下のコマンドをその階層で実行するだけです．

```bash
$ sudo docker compose up --build
```

初回は時間がかかりますが，しばらくするとURLが表示されるので，それにアクセスすればJupyter Labによる基本的な機械学習ライブラリが扱える開発環境が利用できるようになっていると思います．

# 追記
上記の方法でいくつかのサーバを構築していたところ，以下のようなエラーメッセージが出力されたものがありました．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693436/7f731a6e-7c4a-b955-da3b-65c72e249b60.png)

> Your system has UEFI Secure Boot enabled.
> 
> UEFI Secure Boot requires additional configuration to work with third-party drivers.
> 
> The system will assist you in configuring UEFI Secure Boot. To permit the use of third-party drivers, a new Machine-Owner Key (MOK) has been generated. This key now needs to be enrolled in your system's firmware. 
> 
> To ensure that this change is being made by you as an authorized user, and not by an attacker, you must choose a password now and then confirm the change after reboot using the same password , in both the "Enroll MOK" and "Change Secure Boot state" menus that will be presented to you when this system reboots.
> 
> If you proceed but do not confirm the password upon reboot, Ubuntu will still be able to boot on your system but any hardware that requires third-party drivers to work correctly may not be usable. 

いくつかのサイトを見て回ってみたのですが，（私の環境に）合致するような説明がなかったため，最終的に解決した方法を以下の記事にまとめました．

:::note
[Your system has UEFI Secure Boot enabled. UEFI Secure Boot requires ... というエラー（メッセージ）の対処](https://qiita.com/Yorozuya59/items/499a632cce827a912918)

私の検索方法が良くなかったのかもしれませんが，BIOS (UEFI) の設定を変更する方法を掲載している記事がほとんどでした．
そちらの方がメジャーなのかなと思うので，その対処法を試してみてからの方が良いかもしれません．（上記の記事ではUEFIについては触れていません．）
:::