はじめに
利用していたVPSがサービスを終了したため、これまで動かしていたアプリ(Rubyベース)をコンテナ化してSynologyの上へ移行しようと考えた。
移行にあたって手元で気軽に触れるDocker環境を用意したく、WSL上にDocker環境を準備していく。
Docker自体の初心者であるため、ここに備忘録を残す。
なお、WSLのセットアップパートについてはこちら
Dockerのインストール
環境
$ cat /etc/os-release
PRETTY_NAME="Ubuntu 24.04.3 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.3 LTS (Noble Numbat)"
インストール作業
と、いいつつ、やることは公式のマニュアル通り
https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository
下準備
# Add Docker's official GPG key:
$ sudo apt update
$ sudo apt install ca-certificates curl
$ sudo install -m 0755 -d /etc/apt/keyrings
$ sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
$ sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
$ sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF
$ sudo apt update
何をしているかといえば
- sudo apt update: パッケージリストの更新
- sudo apt install ca-certificates curl: ca-certificatesとcurlのインストール
- certificates: CA証明書リスト。これが古いとリポジトリへのアクセスやcurlでのアクセスが失敗することがあるため最新化
- curl: インターネット越しにファイルやコンテンツを取得するソフト。後で使うのでインストール(私の環境にはすでに入っていた。)
- sudo install -m 0755 -d /etc/apt/keyrings: パーミッション指定でディレクトリ作成
- sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc: download.docker.comからgpgファイル(暗号化の署名に使う)を取得しdocker.ascとして格納
- sudo chmod a+r /etc/apt/keyrings/docker.asc: docker.ascのパーミッション変更
- sudo tee /etc/apt/sources.list.d/docker.sources <<EOF: Docker用のリポジトリの追加
- sudo apt update: リポジトリを追加したので再度パッケージリストの更新
Dockerに関連するコンポーネントのインストール
$ sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Dockerサービスの起動
$ sudo systemctl status docker
$ sudo systemctl start docker
Dockerを使ってみる
公式マニュアルのHello Worldイメージを走らせる
dockerコマンドでhello-worldイメージを実行
$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
17eec7bbc9d7: Pull complete
ea52d2000f90: Download complete
Digest: sha256:d4aaab6242e0cace87e2ec17a2ed3d779d18fbfd03042ea58f2995626396a274
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
何が起きたのか?
ローカルには、hello-worldというDockerイメージが存在しないため、リポジトリからhello-worldイメージをpull(ダウンロード)して、そのイメージを実行。
実行結果が、Hello from Docker!から始まるテキスト出力
ダウンロードしてきたリポジトリはどこなのか?
DockerHub: https://hub.docker.com/_/hello-world
その中身は何なのか?
GitHub: https://github.com/docker-library/hello-world
WSL上のDockerの状況を確認してみる
Dockerイメージの一覧を取得してみる。
先ほどダウンロードしたhello-worldのイメージがあるのがわかる。
$ sudo docker image ls
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
hello-world:latest d4aaab6242e0 25.9kB 9.52kB U
実際に走っているDockerコンテナを確認してみる。
が、何もプロセスが走っていない。
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
hello-worldコンテナは、Hello from Docker!から始まるテキスト出力するだけなので、出力が終わるとすぐにプロセスが停止してしまう。
そこで、-a オプションでステータスに関係なくすべてのプロセスを表示させると以下のようにhello-worldコンテナがExitedステータスである。
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9214adaabe96 hello-world "/hello" 3 seconds ago Exited (0) 2 seconds ago hungry_bose
ということで、Dockerイメージをダウンロードしてそのイメージを走らせた結果、Dockerイメージが1つ、Dockerプロセスが1つコマンド結果として出力されることが確認できた。
DockerコンテナとDockerイメージの管理
もう一度hello-worldのDockerを走らせてみる。
$ sudo docker run hello-world
Hello from Docker!
$ sudo docker image ls
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
hello-world:latest d4aaab6242e0 25.9kB 9.52kB U
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
054cb4bd3480 hello-world "/hello" About a minute ago Exited (0) About a minute ago flamboyant_kare
9214adaabe96 hello-world "/hello" 19 minutes ago Exited (0) 19 minutes ago hungry_bose
今度はイメージが存在しているのでダウンロードはせずに、Dockerコンテナだけが走る。
Dockerイメージは変わらないが、DockerのプロセスはExitedステータスが2つとなっている。
すでに終了しているプロセスのため、このままでも良いがこの後いろいろテストする際に残っていると管理が煩雑になるためこれを削除する。
$ sudo docker rm 9214adaabe96
9214adaabe96
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
054cb4bd3480 hello-world "/hello" 6 minutes ago Exited (0) 6 minutes ago flamboyant_kare
指定したコンテナIDのプロセスが消えた。
もう一つのプロセスも消してあげると、DockerイメージのExtraカラムのUが消えてDockerイメージ自体も消せるようになる。
$ sudo docker image ls
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
hello-world:latest d4aaab6242e0 25.9kB 9.52kB
$ sudo docker image rm d4aaab6242e0
Untagged: hello-world:latest
Deleted: sha256:d4aaab6242e0cace87e2ec17a2ed3d779d18fbfd03042ea58f2995626396a274
$ sudo docker image ls
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
これでDockerイメージもコンテナプロセスもまっさらな元の状態に戻った。
なお、Dockerイメージからコンテナを走らせるたびにプロセスが溜まっていくので、それが嫌な場合にはコンテナを走らせるときに以下のように「--rm」オプションをコマンドを打つことで、プロセス終了後にコンテナプロセスを削除してくれる。
$ sudo docker run --rm hello-world
自分で作ったDockerイメージを走らせる
Dockerイメージの作り方
DockerではDockerfileというファイルにそのDockerイメージの定義をして、その定義に則した形でビルドすることでDockerイメージを作成する。
まずはできるだけシンプルなDockerイメージを作成してみる。
使いたいアプリケーションはRubyなので、Rubyが使える環境を作ってみる。
まずは、作業ディレクトリを適当なところに作って、その配下にDockerfileを作成する。
その中身はrubyのverion 4.0.0の環境で、rubyのワンラインコードを実行するというだけのシンプルな内容。
$ cd ~/docker/test_env
$ cat Dockerfile
FROM ruby:4.0.0
CMD ["ruby","-e","puts 'Hello Ruby on Docker!'"]
そしたら、このDockerfileをもとにDockerイメージをビルドしてみる。
-tオプションでイメージの名前を指定しておく。
$ sudo docker build -t ruby-test .
[+] Building 1.2s (5/5) FINISHED docker:default
$ sudo docker image ls
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
ruby-test:latest f5f28bb89334 1.62GB 428MB
Dockerイメージの走らせ方
次に、このイメージからコンテナを走らせてみる。Dockerイメージの名前を指定してRun
無事、Dockerfile内のCMDで指定したRubyコードを解釈して、意図したレスポンスを返してくれた。
$ sudo docker run --rm ruby-test
Hello Ruby on Docker!
これでいつでも、Ruby verison 4.0.0で「Hello Ruby on Docker!」とテキストを出力してくれるDockerコンテナのRubyアプリか完成した。
まぁ、こんなアプリは何の役にも立たないのだが、CMDの部分は引数として渡してあげることができるので、RubyがインストールされていないこのWSL環境で、このコンテナを使うことでRubyコードを走らせることができる。
例えば以下な感じ
sudo docker run --rm ruby-test ruby -v
ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [x86_64-linux]
引数として「ruby -v」を渡してコンテナを走らせたので、DockerfileのCMDで指定した内容が上書きされてruby -vの結果(今回は、Ruby version 4.0.0のコンテナ環境なので、それを示す出力)が表示された。
コンテナからスクリプトを実行してみる
ベースのDockerイメージはruby:latestを使って、予め用意したrubyスクリプトを走らせてみたいと思う。
$ cat sample.rb
puts 'This is run from ' + File.basename(__FILE__)
$ sudo docker run --rm ruby:latest ruby -v
ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [x86_64-linux]
$ sudo docker run --rm ruby:latest ruby ~/docker/test_env/sample.rb
ruby: No such file or directory -- /home/shin/docker/test_env/sample.rb (LoadError)
まず、sample.rbという名前のtext出力と自身のファイル名を返すrubyスクリプトを用意する。
つぎに、ruby:latestコンテナがきちんとRubyを解釈していることを確認する。
で、sample.rbを食わせてみるが、そんなファイルは見当たらないといわれてしまう。
コンテナの中はWSL環境からは隔絶された世界なので、外の世界のパスだけ指定されてもコンテナの中からは見えないのである。
そこで、以下のようにして、sample.rbがあるディレクトリをコンテナの中の世界のディレクトリからマウントさせてコンテナを走らせてみる。
$ sudo docker run --rm -v ~/docker/test_env:/app ruby:latest ruby /app/sample.rb
This is run from sample.rb
-vオプションで、WSLの~/docker/test_envディレクトリをコンテナ側の/appへマウントさせた。
sample.rbのパスも/app/sample.rbと指定してあげることで動作するようになった。
スクリプトを実行するDockerイメージを作る
sample.rbを実行するDockerイメージを作ってみる。
まず、Dockerfileを以下のようにする。
$ cat Dockerfile
FROM ruby:latest
WORKDIR /app
COPY sample.rb /app/sample.rb
CMD ["ruby","/app/sample.rb"]
コンテナ内での作業ディレクトリは/appとして、そこにsample.rbをコピー、その後sample.rbを実行という内容になっている。
$ sudo docker build -t ruby:latest-w-sample .
$ sudo docker run --rm ruby:latest-w-sample
This is run from sample.rb
というわけで、sample.rbを実行してくれるコンテナ(ruby:latest-w-sample)が出来上がった。