プロジェクト

全般

プロフィール

LinuxでDocker

コンテナの設定

コンテナの粒度

1つのコンテナでいくつものプロセスを稼動させるか、1つのコンテナで1つのプロセスを起動させるか、について。

  • sshdを入れてbashで外部から接続してあたかも独立したノードと見せることもできそうだが、それなら仮想マシンの方がよいと思う
  • Redmine(Nginx + Unicorn + MySQL)をDockerで動かすとしたら
    • 構成1) 3つのコンテナを立て、それぞれでNginx、Unicorn、MySQLを個別に稼動
    • 構成2) 1つのコンテナを立て、その中でNginx、Unicorn、MySQLを一緒に稼動
    • 構成3) 2つのコンテナを立て、1つでNginx、Unicornを、もう1つでMySQLを稼動
    • 構成4) 2つのコンテナを立て、1つでNginxを、もう1つでUnicorn、MySQLを稼動
      どれがよいだろう?

Dockerは、アプリケーション単位のコンテナなので、1つのコンテナで1つのプロセスを動かすのが基本。
複数のアプリケーションをまとめて動かすのであれば、Linuxコンテナ(LXC)が向いているようだ。

ケーススタディ1)GrafanaとInfluxDB

主に時系列データを可視化するGrafanaと、時系列データに特化したデータベースInfluxDBと2つのアプリケーションを組み合わせたシステムをDockerで実行します。
Dockerでは、アプリケーション毎に1つのコンテナで動かすのが基本なので、GrafanaのコンテナとInfluxDBのコンテナの2つコンテナを使用します。
また、Dockerは停止するとファイルシステムが

コンテナホストのファイアウォールとコンテナのポート

コンテナホストのファイアウォールでは閉じている(遮断している)ポートを指定してDockerアプリケーションを起動したところ、外部からそのポートへアクセスができてしまう。

これは、Dockerの実行に指定したポートはInboundではなく、仮想ネットワークへ転送される(NAT)仕組みのため、Linuxのファイアウォール設定で閉じていても通信できてしまう。

Rocky Linux 8でDockerの場合

Dockerをインストールしたところ、/etc/firewalld/zones/docker.xmlが生成されていた。

<?xml version="1.0" encoding="utf-8"?>
<zone version="1.0" target="ACCEPT">
  <short>docker</short>
  <description>zone for docker bridge network interfaces</description>
</zone>

publicゾーンとは別にdockerゾーンが生成されている

~$ firewall-cmd --get-active-zones
docker
  interfaces: docker0
public
  interfaces: eth0
~$

ネットワーク

同じサーバー上で動く別コンテナへのアクセス

同じサーバー上であっても異なるコンテナで動作するサービスへは localhost では接続できません。

永続化

Docker コンテナは、イメージからコンテナを生成後、start/stop をしている限りはコンテナ内に作成したファイルは保持されます。しかし、コンテナを破棄して再度イメージからコンテナを生成すると、コンテナ実行中に変更したストレージデータは消えてしまいます。
イメージを更新した場合(例:バージョンアップ)も、コンテナは新たに生成されるので、前のコンテナのストレージデータは引き継ぎできません。

そこで、永続化したいアプリケーションのデータはコンテナの外部に置く必要があります。

永続化の手段

  • volume
  • bind mount

volumeは、dockerが管理する領域の中に永続化データのボリュームを設け、コンテナからそのボリュームをマウントして使用します。
bind mountは、ホストOSの特定ディレクトリをコンテナ内のディレクトリパスにmountして使用します。

ボリューム

  • ボリュームの作成
    docker volume create myvolume

コンテナの管理

コマンド

旧コマンド

コマンド 内容 備考
docker run イメージを取得してコンテナを生成し、コンテナを実行
docker ps コンテナの一覧 -a オプションで全てのコンテナを表示(デフォルトは起動中のコンテナ)
docker start 作成されたコンテナを実行
docker stop 実行中のコンテナを停止
docker rm コンテナを削除
docker image ls ローカルに格納済みのコンテナイメージの一覧
docker pull Docker Hub(公式リポジトリ)から既存のイメージをダウンロード
docker rmi イメージの削除

新コマンド

Docker v1.13以降で使用します。以下はコマンドの抜粋です。

コマンド 内容 備考
docker container run 新しいコンテナでコマンドを実行
docker container start 停止しているコンテナを起動
docker container stop 実行中のコンテナを停止
docker container create 新しいコンテナの作成
docker container rm コンテナの削除
docker container ls コンテナの一覧 -a オプションで全てのコンテナを表示(デフォルトは実行中のコンテナ)
docker container attach 実行中のコンテナにローカルの標準入出力を接続
docker container exec 実行中のコンテナ上でコマンド実行
docker container stats 実行中のコンテナの使用リソースを表示(CPU/Mem/Net/IO)
docker container top コンテナ上で実行されているプロセス一覧
docker image build Dockerfileからコンテナイメージを構築
docker image pull レジストリからイメージを取得
docker image ls イメージの一覧
docker image rm イメージを削除
docker system df dockerの使用ディスク容量を表示
docker system prune 未使用のオブジェクト(コンテナ、イメージ)を削除
docker volume ls ボリュームの一覧
docker volume create ボリュームの作成
docker volume rm ボリュームの削除
docker volume prune 未使用のボリュームをすべて削除
docker container run

runは、コンテナのイメージを公式リポジトリから取得し、コンテナを作成し、コンテナを実行します。
実際には、pullコマンド、createコマンド、runコマンドを一気に実行するのがrunコマンドになります。

書式

docker container run [オプション] IMAGE [COMMAND] [ARGS...]

オプション(抜粋)

  • --detach, -d バックグラウンドでコンテナを実行しIDを表示
  • --interactive, -i アタッチせずとも標準入力を開く
  • --tty, -t 擬似TTYを割り当て
  • --env, -e 環境変数を指定
  • --publish, -p コンテナのポートをホストに公開
  • --name コンテナ名を付与。省略するとランダムな名前(科学者、ソフトウェアの著名人に基づくランダムな氏名)が付与


~$ sudo docker container run -d --name redmine-trial -p 3000:3000 redmine:6.0.3
Unable to find image 'redmine:6.0.3' locally
6.0.3: Pulling from library/redmine
Digest: sha256:cdbf1b0081787842e3e3138f90a1c2df0fbcb81e93a84aa4d4611719741c0ac8
Status: Downloaded newer image for redmine:6.0.3
5d68c8b28aa3deadb2c8497eac3f788878b880ebd0a9fe3722e965aabd735d29

  • ローカルにイメージが存在しないので、dockerリポジトリよりイメージをダウンロードして実行

一度runコマンドを実行して生成したコンテナが停止したとき、コンテナを再実行するには、すでにコンテナが作成済みとなっているのでrunコマンドではなくstartコマンドを使います。

docker container attach

attachは、実行中のコンテナのプロセス(PID=1)を、attach実行ターミナルの標準入力、標準出力、標準エラーに接続します。

docker container exec

execは、実行中のコンテナ上で指定したコマンドを実行します。
よく行われるのは、コンテナ上でbashを実行し、そのbashでshell環境の操作をすることです。その場合、-it オプション指定します。

~$ docker container exec -it mycontainer bash

dockerコマンドの実行でsudoを不要に

sudoでroot権限にならなくてもdockerコマンドを実行できるように、dockerグループにユーザーを追加します。
usermod -aG docker tom

docker compose

複数のプロセスが連携するアプリケーションをDockerで動かす場合、それぞれのプロセスをDockerで起動する必要があります。
docker composeは、この複数のコンテナの組み合わせを管理するコマンドです。

docker compose up

docker-compose.ymlを定義し、そのディレクトリでこのコマンドを実行すると、docker-compose.ymlに定義したコンテナを生成し、実行します。

docker compose down

docker-compose.ymlのあるディレクトリでこのコマンドを実行すると、docker-compose.ymlに定義したコンテナを停止・破棄します。
すなわち、stopとrmを実行します。

docker compose stop

docker-compose.ymlのあるディレクトリでこのコマンドを実行すると、docker-compose.ymlに定義したコンテナを停止します。

docker compose start

docker-compose.ymlのあるディレクトリでこのコマンドを実行すると、docker-compose.ymlに定義したコンテナを開始します。

コンテナのイメージ

コンテナを実行するには、コンテナイメージが必要となる。イメージは外部から取得するか自分で作成するかとなる。
主要なアプリケーションはコンテナイメージが提要されている。

コンテナの状態

状態名 内容
created
running
paused
exited

手順

Grafana

InfluxDB と Grafana を双方 Docker 上で実行します。

docker composeで実行

InfluxDBとGrafanaの2つのDockerコンテナを生成・実行するとき、docker composeを用いると簡単に実行できます。

docker-compose.ymlの作成

docker composeでは、実行するコンテナ群の定義を docker-compose.yml ファイルに記述します。

version: "3" 

services:
  influxdb:
    image: influxdb
    container_name: influxdb
    restart: always
    volumes:
      - ./influxdb:/var/lib/influxdb2
    ports:
      - 8086:8086
      - 8083:8083
    environment:
      DOCKER_INFLUXDB_INIT_MODE: setup
      DOCKER_INFLUXDB_INIT_USERNAME: myname
      DOCKER_INFLUXDB_INIT_PASSWORD: mypassword
      DOCKER_INFLUXDB_INIT_ORG: myorg
      DOCKER_INFLUXDB_INIT_BUCKET: mybucket
      DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: my_secret_token

  grafana:
    image: grafana/grafana
    container_name: grafana
    user: "root" 
    restart: always
    volumes:
      - ./grafana:/var/lib/grafana
    depends_on:
      - influxdb
    ports:
      - 3000:3000
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=admin
  • InfluxDBのアカウント、パスワード、APIトークンなどを記述できます。
    • パスワードは文字数の規定あり(5文字では起動時にエラー)
  • Grafanaのパスワードは初回接続時に変更を促された

イメージの作成

Ubuntuユーザーランドのイメージ作成

まず、作業ディレクトリを作成し、Dockerfileを記述します。

work$ mkdir hello-ubuntu
work$ cd hello-ubuntu
hello-ubuntu$ vi Dockerfile

Dockerfileを作成します。ここでは、ubuntuイメージの最新を取得し、apt update で最新化、apt installで追加パッケージをインストールします。

FROM ubuntu:latest
RUN apt update -y && apt install -y iputils-ping net-tools curl

イメージを作成します。

hello-ubuntu$ docker image build -t test-image:v1 .

イメージが生成されたことを確認

hello-ubuntu$ docker image ls
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
test-image            v1        82e007336365   36 minutes ago   121MB
ubuntu                latest    58db3edaf2be   2 weeks ago      77.8MB

イメージからコンテナを生成し実行します。

hello-ubuntu$ docker run --name test-container1 -it test-image:v1 /bin/bash
  • -it オプションを指定し、標準入力とターミナルを使用

rubyのhello

コンテナイメージの作成

Rubyで動くアプリケーションをDockerコンテナとして作成します。
作業ディレクトリを作成し、その中に Dockerfile の名前でDockerイメージの定義を記載します。

docker$ mkdir hello_ruby
docker$ cd hello_ruby
hello_ruby$ vi Dockerfile
  • Dockerfile
    # syntax=docker/dockerfile:1
    FROM ruby:3.3.7-slim
    
    COPY src/hello.rb .
    
    CMD ["ruby", "hello.rb"]
    

Dockerアプリケーションのランタイム(今回はruby)をベースイメージとします。docker公式リポジトリにある、ruby 3.3系の最新版(3.3.7)のサイズ削減版(slim)を指定します。
hello.rbは、とりあえず root(トップ)ディレクトリに置きます。

  • hello.rb
    puts "Hello, Ruby Docker World!" 
    

Dockerイメージを生成します。

hello_ruby$ docker image build -t hello-ruby:0.1 .
  :
  • -tオプションで、Dockerイメージの <リポジトリ名>:<タグ> を指定します。

生成されたイメージはローカルマシンのDocker領域に置かれるので、管理コマンドで確認します。

hello_ruby$ docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
hello-ruby   0.1       e81943adfb03   13 minutes ago   150MBREPOSITORY    TAG       IMAGE ID       CREATED          SIZE
コンテナの作成・実行

コンテナを作成し、起動します。

hello_ruby$ docker container run --name hello_ruby hello-ruby:0.1
Hello, Ruby Docker World!
hello_ruby$ 

  • docker container runコマンドは、コンテナをイメージから作成し、それを起動します。
~$ docker container ls -a
CONTAINER ID   IMAGE            COMMAND           CREATED          STATUS                      PORTS     NAMES
57fcee1932be   hello-ruby:0.1   "ruby hello.rb"   43 seconds ago   Exited (0) 42 seconds ago             hello_ruby

一度作成したコンテナが停止後、再度実行するときは docker container run ではなく、 docker container start コマンドを使用します。

~$ docker container start -a hello_ruby
Hello, Ruby Docker World!
~$
  • -aオプションを指定しないと、デフォルトのコマンドが実行されません。

メモ

困ったこととその解決

すぐに実行が終わるコンテナにインタラクティブに接続

コンテナ起動後、コンテナ内でコマンドがすぐに終了してしまう場合、attachやexecで接続することができません。
その場合、一度コンテナを破棄し、docker container run -itオプション付きでコンテナを生成・実行します。

参考資料

Linux女子部「Docker勉強会」資料(2014-06-19 講師: 中井悦司 氏)


18日前に更新