Ubuntu Weekly Recipe

第719回UbuntuでDocker Desktop for Linuxを使う

Docker Desktopとは

最近のトレンドのひとつに「コンテナ」があります。高速に独立したアプリケーション実行環境を作れる「Docker」は、アプリ開発者からシステム運用者まで、幅広く活用されているソフトウェアです。

DockerをMacやWindows上で簡単に扱えるよう、Dockerデーモン、CLIコマンド、GUIフロントエンド等々とあわせてパッケージングしたプロダクトが「Docker Desktop」です。そのDocker Desktopが、最近ついにLinuxに対応しました

Dockerなら昔からLinux上で動くし、パッケージも用意されているし、別にGUIとかいらないし、何の意味があるかわからないよ……という方も多いでしょう。またDocker Desktopが有料化されたというニュースを聞いて、抵抗を感じる方もいるかもしれません。

結論から言ってしまうと、Docker Desktopを使うメリットのひとつは、ホスト環境ごとの違いをなくせる点です。Docker DesktopはWindows/Mac/Linux版が存在しますが、機能的な違いはありません。そのため開発者の使用するOSが混在しているような環境でも、バージョンを揃えるだけで、手軽に共通の開発環境を整えることができます。そしてDocker Desktopが有料化されたのは事実ですが、中小企業や個人用途であれば、現在でも無料で使えます。こう聞くと、なんだか魅力的に見えてくるのではないでしょうか。

それではUbuntu上でDocker Desktop for Linux(以下DD4L)を使う具体的な方法を、その機能と合わせて詳しく紹介していきましょう。

Ubuntu 22.04 LTSにDD4Lをインストールする

まずベースとなるUbuntu 22.04 LTS環境を用意しましょう。DD4Lの動作に必要な環境は以下の通りです。現在のUbuntuデスクトップが動作しているのであれば、特に問題となる箇所はないでしょう。

  • 仮想化支援機能を搭載した64bit CPU
  • 64bitカーネル
  • Kernel-based Virtual Machine(KVM)
  • QEMU バージョン5.2以降
  • systemd
  • GNOMEもしくはKDEデスクトップ環境
  • 4GB以上のメモリ

なぜコンテナを動かすのにKVM?と思うかもしれません。実はDD4Lはホストマシン上で直接ではなく、仮想マシンを作成した上で、その中でDockerデーモンを動作させます。これは、WindowsやMac上のDocker Desktopとの差異をなくすためや、LTSバージョンのOS上でも最新のカーネルの機能を提供するためなど、いくつかの理由によるものです。詳しくは公式ドキュメントのWhy Docker Desktop for Linux runs a VMを参照してください。QEMUのバージョン5.2以降が要求されているのは、virtiofsが必要な都合上です。QEMUのバージョンが4.2のUbuntu 20.04 LTSでも、DD4Lは起動することはします。しかし正式にサポートされているバージョンではないため、22.04 LTSの利用を強く推奨します。

なおDocker用の仮想マシンを動かさなくてはならない都合上、DD4LのホストとなるUbuntu自体が仮想マシン内で動作している場合は、Nested VMを有効にする必要があります。例えばVirtualBoxであれば、VirtualBoxのホスト上で以下のコマンドを実行して、ネステッドVT-x/AMD-Vを有効化してください。

ネステッドVT-x/AMD-Vを有効化する
$ VBoxManage modifyvm 'VM名' --nested-hw-virt on

DD4Lは、公式が提供しているUbuntu向けのDebパッケージからインストールできます。ただしDD4Lはdocker-ce-cliパッケージに依存しているため、インストールに先立って、Dockerの公式リポジトリを追加しておく必要があります。以下のコマンドを実行して、リポジトリ鍵とAPTラインを追加してください。

依存パッケージをインストールするため、Docker公式のリポジトリを追加しておく
$ sudo apt update && sudo apt install -y curl
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/docker.gpg
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt update

ダウンロードページを開き、Debパッケージをダウンロードしてください。本記事執筆時点(2022年6月)では、バージョン4.9.0が最新でした。ダウンロードしたファイルをaptコマンドでインストールします。

図1 DD4LのDebパッケージをダウンロードする
図1
docker-desktopパッケージのインストール
$ sudo apt install ./docker-desktop-4.9.0-amd64.deb

DD4Lの起動とコンテナの管理

インストールが完了したら、Superキーを押して「docker」と検索し、DD4Lを起動してください。

図2 DD4Lの起動
図2

初回起動時は図3のような利用規約への同意画面が表示されます。DockerにはDocker Subscription Service Agreementというサブスクリプションサービス契約があり、Docker Desktopはこの影響を受けるプロダクトです。簡単に言えば、Docker Desktopは個人や中小企業での利用であれば無料ですが、一定の規模以上の企業で利用するのであれば、有償のサブスクリプション契約が必要になります。詳細は公式ブログを参照してください。

図3 Docker Subscription Service Agreementを確認した上で同意する必要がある
図3

問題がなければ「I accept the terms」にチェックを入れた上で、⁠Accept」をクリックしてください。DD4Lが起動すると、図4のような画面が開きます。

図4 DD4Lのホーム画面
図4

それでは実際にコンテナを起動してみましょう。ホーム画面にいくつか定番のコンテナイメージがリストアップされています。ここではUbuntuのイメージの「Run」をクリックしてみましょう。すると自動的にリポジトリからUbuntuのイメージがPullされ、コンテナインスタンスが起動します。

図5 Ubuntuコンテナが起動した状態。Launch terminalをクリックするとコンテナ内のシェルを取ることができる
図5
図6 裏側で動作しているのは普通のDockerのため、dockerコマンドで直接操作することもできる。これはdocker execを実行してターミナルからコンテナのシェルを取った例
図6

別のコンテナも起動してみましょう。今度はホーム画面から、NGINXのイメージの「Run」をクリックしてみます。すると図7のようなダイアログが表示されます。

図7 NGINXコンテナ起動時に表示されるダイアログ。NGINXで公開するホスト上のディレクトリを指定する
図7

NGINXはWebサーバーですから、コンテンツを公開するディレクトリが必要になります。ここで指定したホスト上のディレクトリをコンテナ内にマウントし、Webサーバーで公開できるという仕組みです。例えば以下のコマンドを実行し、~/wwwディレクトリ内に「hello, world」とだけ書かれたファイルを用意し、コンテナにマウントしてみます。

ディレクトリを作成し、シンプルなHTML(という名のテキスト)を用意してみた
$ mkdir ~/www
$ echo 'hello, world' > ~/www/index.html

コンテナが起動すると、今度はOverviewにURLが表示されました。このURL(localhost:55000)で、コンテナ内のNGINXにアクセスできます。

図8 NGINXコンテナが起動した状態。コンテナの標準出力に出力されている、サーバーのアクセスログが表示されている
図8
図9 http://localhost:55000にホストマシンのブラウザからアクセスした例。先ほど作成したindex.htmlが表示されているのがわかる
図9

左ペインから「Containers」をクリックすると、現在起動中のコンテナの一覧を表示できます。ここからコンテナの停止や再起動、削除といった管理が可能です。

図10 動作中のコンテナの一覧。UbuntuコンテナとNGINXコンテナが起動しているのがわかる
図10

「Images」をクリックすると、ローカルに存在するコンテナイメージを表示できます。ここではイメージのPullやリモートリポジトリへのPush、不要になったイメージの削除といったイメージの管理全般を行えます。イメージ名の右側に表示されているケバブメニューから「Inspect」をクリックすると、そのイメージがどのようにビルドされたかの履歴を確認できます。DockerHubへサインイン済みの場合は、リモートリポジトリの内容も参照できます。そして当然ですが、ここからイメージを選択してコンテナインスタンスを起動することもできます。

図11 イメージの一覧を表示した例。先ほど起動した際にPullされた、UbuntuとNGINXのイメージが確認できる
図11
図12 NGINXイメージの履歴を表示した例
図12

docker-composeを使う

DD4Lでは、デフォルトでCompose V2が使えます。docker-compose.ymlを用意して、⁠docker compose」コマンドを実行すれば、WebアプリコンテナとDBコンテナといった、複数のコンテナを簡単に管理できます。

注意点としては、Compose V1である従来のdocker-composeコマンドはインストールされていない点です。互換性の都合といった理由で、どうしてもdocker-composeコマンドを使いたい場合は、設定の「General⁠⁠→⁠Enable Docker Compose V1/V2 compatibility mode」にチェックを入れてください。/usr/local/bin以下に、dockre-composeというシンボリックリンクが作成されます(ただし内部的にはdocker composeコマンドを呼び出します⁠⁠。

図13 docker composeコマンドで起動したコンテナ群は、GUI上からもグループ化されて見える。一度コンテナを作成してしまえば、以後はGUI上からまとめて起動や停止が可能になる
図13

Kubernetesを動かす

コンテナの話題となれば、みんな大好きKubernetes(以下k8s)は欠かせません。とはいえ自前できちんとしたk8s環境を構築するのはなかなか手間ですし、かといってAWSのEKSやGCPのGKEは、クラスターを維持するだけで結構な料金がかかりますよね。

手軽なお試し環境でよければ、過去にも紹介したように、snapパッケージのmicrok8sを使うのが簡単です。ところがDD4Lを使えば、もっと簡単にk8s環境を用意できます。というのもDD4Lにはk8sがビルトインされており、設定のGUIからチェックを入れるだけで、シングルノードクラスターを自動的に起動させることができるのです。

ウィンドウ右上の歯車アイコンをクリックして、⁠Kubernetes」を開いてください。⁠Enable Kubernetes」にチェックを入れてから「Apply & Restart」をクリックすると、k8sが起動します。

図14 デフォルトでは、k8sのシステムコンテナ(kube-proxyやcorednsなど)はDD4Lのコンテナ一覧には表示されない。⁠Show system containers」にチェックを入れることで表示させることもできるが、自分で起動したコンテナの見通しが悪くなるため、やらないほうがいいだろう
図14
図15 DD4Lのコンテナ一覧には表示されないが、docker psを実行すると、k8s関連のコンテナが起動しているのがわかる
図15

この段階でホームディレクトリ内の~/.kube/configにKUBECONFIGが作成されます。そのためkubectlコマンドをインストールするだけで、DD4L上のk8sクラスターを操作可能です。kubectlコマンドは、snapを使ってインストールするのが簡単でしょう[1]⁠。

ただし、k8sクラスターとkubectlコマンドのバージョンの違いには注意してください。DD4L 4.9.0では、k8s 1.24.0のクラスターがデプロイされます。DD4Lのバージョンが上がっていくと、新規にデプロイされるクラスターのバージョンもその時期に応じて上がっていきますが、デプロイ済みのクラスターは自動的にアップグレードされません。そのためkubectlをデフォルトの「latest/stable」チャンネルからインストールしてしまうと、snapパッケージの自動更新によって、クライアントとクラスターのバージョンが乖離してしまう可能性があります。この問題を防ぐためには、kubectlのリリースチャンネルを明示的に指定して、バージョンを揃えるのがお勧めです。

リリースチャンネルを1.24/stableに指定してインストールする例と、インストール済みのkubectlのチャンネルを変更する例
$ sudo snap install kubectl --channel=1.24/stable --classic
$ sudo snap switch kubectl --channel=1.24/stable
図16 kubectlコマンドの実行例。docker-desktopというノード1台で構成され、kube-system名前空間にPodが起動しているのがわかる
図16

実際にk8s上にサービスを起動してみましょう。ここでは例として、HTTPのリクエストをそのまま表示する「echoserver」を起動してみます。まず以下の内容で「echoserver.yml」というマニフェストファイルを作成してください。

echoserverのマニフェスト
apiVersion: v1
kind: Namespace
metadata:
  labels:
    app: echoserver
  name: echoserver
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: echoserver
  name: echoserver
  namespace: echoserver
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: echoserver
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: echoserver
  name: echoserver
  namespace: echoserver
spec:
  replicas: 2
  selector:
    matchLabels:
      app: echoserver
  template:
    metadata:
      labels:
        app: echoserver
    spec:
      containers:
      - image: gcr.io/kubernetes-e2e-test-images/echoserver:2.2
        imagePullPolicy: Always
        name: echoserver
        ports:
        - containerPort: 8080

続いて以下のコマンドで、マニフェストを適用します。

kubectl applyコマンドでマニフェストをクラスターに適用する
$ kubectl apply -f echoserver.yml

kubectlコマンドを使って、echoserver名前空間内にふたつのPodと、NodePortのサービスが作成されていることを確認します。

図17 割り当てられているポート(ここでは31367)はブラウザからのアクセスに必要になるため、覚えておく
図17

Webブラウザを開き、⁠http://localhost:(サービスのポート)」にアクセスしてください。echoserverの画面が表示されれば成功です。

図18 echoserverにブラウザからアクセスした画面。リクエストの情報やリクエストヘッダが表示される
図18

このようにDD4Lを使えば、簡単にシングルノードのk8sクラスターを用意できます。ローカルでのテストやデバッグに役立つのではないでしょうか。

別のDockerデーモンとの共存について

DD4Lは、仮想マシン内の独立した空間でDockerデーモンを起動します。そしてDD4Lは、ホストマシン上に直接インストールされた、別のDockerデーモンと共存させることができます。

Dockerには「コンテキスト」と呼ばれる仕組みが存在します。コンテキストにはDockerデーモンのエンドポイントをはじめとする情報が含まれており、このコンテキストを切り替えることで、ひとつのdockerコマンドから、複数のバックエンドを選択して操作することができるのです。

通常Dockerをインストールすると、エンドポイントがローカルのunix:///var/run/docker.sockというソケットを向いた、defaultという名前のコンテキストが作成されます。対してDD4Lは、インストール時にdesktop-linuxという名前で、エンドポイントがホームディレクトリ内の~/.docker/desktop/docker.sockを向いた専用のコンテキストを作成します。そしてDD4Lは、起動時にdockerコマンドがdesktop-linuxコンテキストを利用するよう切り替え、終了時にはdefaultコンテキストに切り戻すという動作を行います。そのためホスト上で別のDockerデーモンが動作していても、DD4Lの起動中のみ、dockerコマンドはDD4LのDockerデーモンと対話するようになるのです。

とはいえ複数のDockerデーモン自体は共存できると言っても、当然コンテナはそれぞれで別管理となるため、どんなコンテナが起動しているかの見通しが悪くなるといったデメリットもあります。起動したコンテナがホストのポートを奪い合うといったトラブルも起きがちですので、筆者としてはあまりお勧めしません。日常的にDD4Lを使うのであれば、ホスト上のDockerデーモンは停止するか、アンインストールしてしまうほうが安心でしょう。

DD4L起動中にdocker context listコマンドを実行した例。desktop-linuxコンテキストに切り替わっていることがわかる。
$ docker context list
NAME                TYPE                DESCRIPTION                               DOCKER ENDPOINT                                   KUBERNETES ENDPOINT   ORCHESTRATOR
default             moby                Current DOCKER_HOST based configuration   unix:///var/run/docker.sock                                             swarm
desktop-linux *     moby                                                          unix:///home/mizuno/.docker/desktop/docker.sock

なおパッケージの依存関係の都合上、本記事の手順でインストールしたDD4Lと、Ubuntuが提供しているdocker.ioパッケージを共存させることはできません。共存させたい場合はDocker公式が提供しているdocker-ceパッケージを利用してください。

Docker Extensionsを利用する

Docker Desktopを使うメリットのひとつが、Docker Extensionsです。現時点ではまだベータ版の機能ではあるもの、サードパーティ製のツールを追加することで、Docker Desktopの機能を拡張できます。

左ペインの「Add Extensions」をクリックしてください。MarketplaceにあるExtensionsの一覧が表示されますので、インストールしたいExtensionsの「Install」ボタンをクリックしてください。

図19 ExtensionsのMarketplaceの画面。ここからインストールしたいExtensionsを探してInstallボタンをクリックする。ただしまだExtensionsの数は少ない
図19

筆者が便利だなと思ったExtensionsが、⁠Logs Explorer」です。通常コンテナのログを確認しようと思うと、docker psでコンテナIDを調べ、docker logsコマンドを実行する必要があります。ログをtailしたければ、-fオプションをつけて、ターミナルを開きっぱなしにしなければなりません。負荷分散のために複数のNGINXコンテナを起動しているような場合は、すべてのコンテナのアクセスログを束ねて監視したいですよね。そうなるともう面倒くさすぎます[2]⁠。

Log Explorerは、起動中のコンテナのログを横断的に検索できるExtensionsです。複数コンテナのログを時系列に並べて一括表示できるだけでなく、コンテナ単位での絞り込み、キーワード検索、標準出力/標準エラー出力でのフィルタが可能です。

図20 Logs Explorerの画面。docker logsコマンドを使ったことがある人であれば、これだけで便利さが理解できると思う
図20

「Disk Usage」Extensionsは、Dockerが利用しているディスク容量を可視化してくれます。⁠Reclaim space」ボタンをクリックすると、停止しているコンテナや不要なイメージ、ボリューム、ビルドキャッシュなどを選択して削除できます。

図21 Disk Usageの画面。ディスク容量が逼迫したような場合は、不要なデータが多く溜まっていないかチェックしてみるとよいだろう
図21

「Anchore」Extensionsは、コンテナイメージの脆弱性をチェックできます。コンテナのセキュリティを高めるためにも、自分でビルドしたイメージはもちろん、DockerHubから入手したイメージのチェックに役立ててみてください。

図22 ローカルに保存されているコンテナイメージの一覧が、インストールされているパッケージと、脆弱性の数とともに表示される
図22
図23 特定のイメージ名をクリックすると、パッケージ名、パッケージバージョンとともに、影響するCVEと緊急度も確認できる
図23

おすすめ記事

記事・ニュース一覧