NICE DCV サーバーをセットアップした Ubuntu インスタンスを AWS CDK で構築してみた

2024.04.16

こんにちは、CX 事業本部製造ビジネステクノロジー部の若槻です。

NICE DCV は、高性能なグラフィックスアプリケーションでの利用に適したリモートデスクトッププロトコルです。

今回は、NICE DCV サーバーをセットアップしたUbuntuディストリビューションの EC2 インスタンスをAWS CDKで構築してみたので手順を紹介します。

やってみた

使用するインスタンス AMI

使用したインスタンスは、AMI Catalog に登録されている下記の非 GPU の Ubuntu ディストリビューションです。

Ubuntu Server 22.04 LTS (HVM), SSD Volume Type (64-bit (x86))

NICE DCV は GPU インスタンスで動作させるようなグラフィックスアプリケーションの利用に向いているのですが、今回は理由(わけ)があって非 GPU インスタンスを使用しました。

なお、同じ非 GPU インスタンスでの NICE DCV のセットアップを手動で行う場合の手順は以下の記事が参考になります。

ユーザーデータとなるシェルスクリプト

NICE DCV サーバーのセットアップスクリプトとなるシェルスクリプトです。これを user data(ユーザーデータ)に記述して、EC2 インスタンスの初回起動時に実行されるようにします。

script/setupDcvServer.sh

# Linux NICE DCV サーバーの前提条件
# @see: https://docs.aws.amazon.com/ja_jp/dcv/latest/adminguide/setting-up-installing-linux-prereq.html
## デスクトップ環境とデスクトップマネージャーをインストールする

### apt update または install 実行時の「Daemons using outdated libraries」ダイアログ表示の抑制
### @see: https://gist.github.com/fernandoaleman/c3191ed46c977f0a3fcfbdac319183fc
sudo sed -i "s/#\$nrconf{restart} = 'i';/\$nrconf{restart} = 'a';/g" /etc/needrestart/needrestart.conf

### デスクトップ環境とデスクトップマネージャーをインストールする
sudo apt update
sudo apt install ubuntu-desktop -y
sudo apt install gdm3

### GDM3 を起動する(GDM3 がアクティブでない場合があるため)
sudo systemctl start gdm3

### GDM3 をデフォルトのデスクトップマネージャーに設定する
sudo dpkg-reconfigure gdm3

### apt upgrade 実行時の「Pending kernel upgrade」ダイアログ表示の抑制
### @see: https://askubuntu.com/questions/1349884/how-to-disable-pending-kernel-upgrade-message
sudo sed -i "s/#\$nrconf{kernelhints} = -1;/\$nrconf{kernelhints} = -1;/g" /etc/needrestart/needrestart.conf

### ソフトウェアパッケージをインストールする
sudo apt upgrade -y

## Wayland プロトコルを無効にする
### [daemon] セクションで WaylandEnable を false に設定する
sudo sed -i -e "s/^#WaylandEnable=false/WaylandEnable=false/g" /etc/gdm3/custom.conf

### GDM サービスを再起動する
sudo systemctl restart gdm3

## X サーバーを設定する
### Linux サーバーの起動時に自動的に起動するように X サーバーを設定する
sudo systemctl set-default graphical.target

### X サーバーを起動する
sudo systemctl isolate graphical.target

### 確認コマンド:出力があること(Xサーバーが実行中であること)を確認する
ps aux | grep X | grep -v grep

## glxinfo ユーティリティをインストールする
sudo apt install mesa-utils -y

## グラフィックスインスタンス用の GPU ドライバーをインストールする
### ※ GPU インスタンスの場合のみ

## GPU 以外のインスタンスに XDummy ドライバーをインストールする
### xDummy ドライバーをインストールする
sudo apt install xserver-xorg-video-dummy

### xorg.conf で xDummy を設定する
sudo bash -c 'cat > /etc/X11/xorg.conf' << EOF
Section "Device"
    Identifier "DummyDevice"
    Driver "dummy"
    Option "UseEDID" "false"
    VideoRam 512000
EndSection

Section "Monitor"
    Identifier "DummyMonitor"
    HorizSync   5.0 - 1000.0
    VertRefresh 5.0 - 200.0
    Option "ReducedBlanking"
EndSection

Section "Screen"
    Identifier "DummyScreen"
    Device "DummyDevice"
    Monitor "DummyMonitor"
    DefaultDepth 24
    SubSection "Display"
        Viewport 0 0
        Depth 24
        Virtual 4096 2160
    EndSubSection
EndSection
EOF

### X サーバーを再起動して、変更を有効にする
sudo systemctl isolate multi-user.target
sudo systemctl isolate graphical.target

# Linux に NICE DCV サーバーをインストールする
# @see: https://docs.aws.amazon.com/ja_jp/dcv/latest/adminguide/setting-up-installing-linux-server.html
## NICE DCV の作業ディレクトリを作成して移動する
mkdir -p /home/ubuntu/dcv && cd $_

## NICE GPG キーをインポートする
wget https://d1uj6qtbmh3dt5.cloudfront.net/NICE-GPG-KEY
gpg --import NICE-GPG-KEY

## NICE DCV パッケージをダウンロードする
wget https://d1uj6qtbmh3dt5.cloudfront.net/2023.1/Servers/nice-dcv-2023.1-16388-ubuntu2204-x86_64.tgz

## .tgz アーカイブのコンテンツを抽出し、抽出されたディレクトリに移動する
tar -xvzf nice-dcv-2023.1-16388-ubuntu2204-x86_64.tgz && cd nice-dcv-2023.1-16388-ubuntu2204-x86_64

## NICE DCV サーバーをインストールする
sudo apt install ./nice-dcv-server_2023.1.16388-1_amd64.ubuntu2204.deb -y

## dcv ユーザーを video グループに追加
sudo usermod -aG video dcv

## ホームディレクトリに戻り、ダウンロードした .tgz アーカイブを削除する
cd /home/ubuntu
sudo rm dcv/nice-dcv-2023.1-16388-ubuntu2004-x86_64.tgz

# インストール後のチェック
# @see: https://docs.aws.amazon.com/ja_jp/dcv/latest/adminguide/setting-up-installing-linux-checks.html
## X サーバーがアクセス可能であることを確認する
### X サーバーを再起動する
sudo systemctl isolate multi-user.target
sudo systemctl isolate graphical.target

### 確認コマンド: "SI:localuser:dcv" が返ることを確認する
sudo DISPLAY=:0 XAUTHORITY=$(ps aux | grep "X.*\-auth" | grep -v grep | sed -n 's/.*-auth \([^ ]\+\).*/\1/p') xhost | grep "SI:localuser:dcv$"

### 同コマンドを2回実行しなければ "SI:localuser:dcv" が返らない場合がある
sudo DISPLAY=:0 XAUTHORITY=$(ps aux | grep "X.*\-auth" | grep -v grep | sed -n 's/.*-auth \([^ ]\+\).*/\1/p') xhost | grep "SI:localuser:dcv$"

# NICE DCV サーバー が Linux で自動的に起動するように設定する
# @see: https://docs.aws.amazon.com/ja_jp/dcv/latest/adminguide/manage-start.html
sudo systemctl enable dcvserver

# 自動コンソールセッションの有効化
# @see: https://docs.aws.amazon.com/ja_jp/dcv/latest/adminguide/managing-sessions-start.html#managing-sessions-start-auto
## Linux NICE DCV サーバー で自動コンソールセッションを有効にする
sudo sed -i -e "s/^#create-session/create-session/g" /etc/dcv/dcv.conf
sudo sed -i -e "s/^#owner = \"\"/owner = \"ubuntu\"/g" /etc/dcv/dcv.conf

## NICE DCV サービスを再起動する
sudo systemctl restart dcvserver

## 確認コマンド: 'console' セッションが作成されていることを確認する
dcv list-sessions

CDK コード

AWS CDK で、前述のユーザーデータを使った EC2 インスタンスを構築するためのコード(TypeScript)を作成します。

lib/cdk-sample-stack.ts

import { aws_ec2, aws_s3, Stack, Duration } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as fs from 'fs';
import * as path from 'path';

export class CdkSampleStack extends Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    const vpcCidr = '10.100.0.0/16';
    const instanceAmiId = 'ami-0eba6c58b7918d3a1'; // Ubuntu Server 22.04 LTS (HVM), SSD Volume Type (64-bit (x86))
    const region = 'ap-northeast-1';
    const ec2InstanceConnectSourceIpRange = '3.112.23.0/29';

    // VPC を作成
    const vpc = new aws_ec2.Vpc(this, 'Vpc', {
      ipAddresses: aws_ec2.IpAddresses.cidr(vpcCidr),
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: 'public',
          subnetType: aws_ec2.SubnetType.PUBLIC,
        },
      ],
      maxAzs: 1, // 開発環境のため AZ は 1 つのみ
    });

    // セキュリティグループを作成
    const securityGroup = new aws_ec2.SecurityGroup(this, 'SecurityGroup', {
      vpc,
    });

    // セキュリティグループに EC2 Instance Connect 用のインバウンドルールを追加
    securityGroup.addIngressRule(
      aws_ec2.Peer.ipv4(ec2InstanceConnectSourceIpRange),
      aws_ec2.Port.tcp(22),
      'SSH by EC2 Instance Connect in ap-northeast-1'
    );

    // EC2 インスタンスを作成
    const instance = new aws_ec2.Instance(this, 'Instance', {
      vpc,
      securityGroup,
      instanceType: aws_ec2.InstanceType.of(
        aws_ec2.InstanceClass.T3,
        aws_ec2.InstanceSize.MEDIUM
      ),
      machineImage: aws_ec2.MachineImage.genericLinux({
        [region]: instanceAmiId,
      }),
      requireImdsv2: true,
    });

    // インスタンスに DCV ライセンスが配置されたバケットへの読み取り権限を付与
    aws_s3.Bucket.fromBucketName(
      this,
      'DcvLicenseBucket',
      `dcv-license.${region}`
    ).grantRead(instance, '*');

    // DCV サーバーのセットアップスクリプトを読み込み
    const setupDcvServerCommands = fs
      .readFileSync(
        path.resolve(__dirname, '../script/setupDcvServer.sh'),
        'utf-8'
      )
      .split('\n');

    // インスタンスのユーザデータにコマンドを追加
    instance.userData.addCommands(...setupDcvServerCommands);
  }
}

上記を CDK デプロイして、EC2 インスタンスを作成します。

なお、今回は cfn-signal を使用していないため、CloudFormation によるリソースのデプロイ完了後もユーザーデータの実行完了を待つ必要があります。完了まではおよそ 15 分掛かります。

Ubuntu ユーザーのパスワード設定

作成されたインスタンスに EC2 Instance Connect で接続します。

次のコマンドを実行して、NICE DCV のコンソールセッションが作成されていれば、NICE DCV サーバーのセットアップは完了しています。

$ dcv list-sessions
Session: 'console' (owner:ubuntu type:console)

下記のコマンドを実行して、ubuntu ユーザーのパスワードを設定します。

sudo passwd ubuntu

インスタンスへの接続許可 IP アドレスの設定

マネジメントコンソールからインスタンスが属しているセキュリティグループの詳細ページにアクセスし、インバウンドルールに以下のルールを追加します。

タイプ カスタム TCP
プロトコル TCP
ポートの範囲 8443
ソース 現在の接続元IPアドレス

これにより、NICE DCV クライアントからインスタンスへのネットワーク接続を許可します。

NICE DCV クライアントのインストール

下記を参考に NICE DCV クライアントをローカルマシンにインストールします。

今回は M1 Mac にインストールした NICE DCV クライアントで接続をします。

NICE DCV クライアントからインスタンスへの接続

マネジメントコンソールからインスタンスの詳細ページにアクセスし、インスタンスのパブリック IPv4 アドレスを確認します。

NICE DCV クライアントで次の情報を入力して Carla サーバーに接続します。

NICE DCV 接続先サーバー インスタンスのパブリック IPv4 アドレス
Ubuntu ユーザー ID ubuntu
Ubuntu ユーザーパスワード 前述の手順で設定したパスワード

NICE DCV クライアントを立ち上げたら、接続先サーバーにインスタンスのパブリック IPv4 アドレスを入力します。

接続を信頼するかどうかを確認するダイアログが表示されるので、接続を許可します。

ユーザー名 Ubuntu とパスワードを入力してログインします。

すると Ubuntu デスクトップのログイン画面が表示されます。

先ほどと同じパスワードを入力してログインします。

ログインすると、NICE DCV サーバーの Ubuntu のデスクトップが表示されました。

トラブルシュート

NICE DCV クライアントで接続をしようとした際に、いくつかのトラブルシュートが発生しました。

Ubuntu のログイン画面で固まる

Ubuntu のデスクトップのログイン画面でログインをしようとした際に、下記の画面で固まる場合がありました。

これはインスタンスタイプを t2.micro のような小さいクラスおよびサイズに設定した場合に発生し、前述のコードで示した t3.medium のような中程度のクラスおよびサイズに設定することで解消しました。

「No license available.」というエラーとなる

NICE DCV クライアントのログイン画面でログインをしようとすると、No license available. というエラーになる場合がありました。

これは、NICE DCV サーバーのインスタンスからライセンスファイルが配置されている S3 バケットに接続できない場合に発生します。インスタンスプロファイルに適切なロールがアタッチされているか確認してください。

おわりに

NICE DCV サーバーをセットアップした Ubuntu ディストリビューションの EC2 インスタンスを AWS CDK で構築してみたので手順を紹介しました。

セットアップ用のシェルスクリプトはユーザーデータだけでなく、そのまま NICE DCV サーバーの手動構築手順としても利用できるので、ぜひ参考にしてみてください。

以上