Ubuntu20.04でDockerコンテナのリバースプロキシとしてTraefikv2を使用する方法

提供:Dev Guides
移動先:案内検索

著者は、 Write for DOnations プログラムの一環として、 Girls WhoCodeを選択して寄付を受け取りました。

序章

Docker は、本番環境でWebアプリケーションを実行するための効率的な方法ですが、同じDockerホストで複数のアプリケーションを実行したい場合があります。 この状況では、リバースプロキシを設定する必要があります。 これは、ポート80443のみを他の世界に公開したいためです。

Traefik は、監視ダッシュボードを含むDocker対応のリバースプロキシです。 Traefik v1はしばらくの間広く使用されており、この以前のチュートリアルに従ってTraefik v1 をインストールできます)。 ただし、このチュートリアルでは、Traefik v2をインストールして構成します。これには、かなりの違いが含まれています。

Traefik v1とv2の最大の違いは、フロントエンドバックエンドが削除され、それらを組み合わせた機能がルーターミドルウェア、およびサービス。 以前は、バックエンドがリクエストに変更を加え、そのリクエストを処理することになっているものにそのリクエストを取得するという仕事をしていました。 Traefik v2は、サービスに送信する前に要求を変更できるミドルウェアを導入することにより、関心の分離を強化します。 ミドルウェアを使用すると、さまざまなルートで使用される可能性のある単一の変更ステップを簡単に指定して、それらを再利用できるようになります(HTTP基本認証など。これについては後で説明します)。 ルーターは、さまざまなミドルウェアを使用することもできます。

このチュートリアルでは、リクエストを2つの異なるWebアプリケーションコンテナ(WordpressコンテナとAdminerコンテナ)にルーティングするようにTraefik v2を構成し、それぞれがMySQLと通信します。データベース。 Let's Encrypt を使用して、HTTPS経由ですべてを提供するようにTraefikを構成します。

前提条件

このチュートリアルを完了するには、次のものが必要です。

ステップ1—Traefikの構成と実行

Traefikプロジェクトには公式Dockerイメージがあるため、これを使用してDockerコンテナーでTraefikを実行します。

ただし、Traefikコンテナを起動して実行する前に、構成ファイルを作成し、暗号化されたパスワードを設定して、監視ダッシュボードにアクセスできるようにする必要があります。

htpasswdユーティリティを使用して、この暗号化されたパスワードを作成します。 まず、apache2-utilsパッケージに含まれているユーティリティをインストールします。

sudo apt-get install apache2-utils

次に、htpasswdを使用してパスワードを生成します。 secure_passwordを、Traefik管理者ユーザーに使用するパスワードに置き換えます。

htpasswd -nb admin secure_password

プログラムからの出力は次のようになります。

Outputadmin:$apr1$ruca84Hq$mbjdMZBAG.KWn7vfN/SNK/

Traefik構成ファイルでこの出力を使用して、Traefikヘルスチェックおよび監視ダッシュボードのHTTP基本認証を設定します。 後で貼り付けることができるように、出力行全体をコピーします。

Traefikサーバーを構成するには、TOML形式を使用してtraefik.tomlおよびtraefik_dynamic.tomlという2つの新しい構成ファイルを作成します。 TOML は、INIファイルに似た構成言語ですが、標準化されています。 これらのファイルを使用すると、Traefikサーバーと、使用するさまざまな統合またはprovidersを構成できます。 このチュートリアルでは、Traefikで利用可能な3つのプロバイダー、apidocker、およびacmeを使用します。 これらの最後のacmeは、Let'sEncryptを使用したTLS証明書をサポートしています。

nanoまたはお好みのテキストエディタを使用して、traefik.tomlを作成して開きます。

nano traefik.toml

まず、構成ファイルのentryPointsセクションを使用して、Traefikがリッスンするポートを指定します。 ポート80443でリッスンするため、2つ必要です。 これらをweb(ポート80)およびwebsecure(ポート443)と呼びましょう。

次の構成を追加します。

traefik.toml

[entryPoints]
  [entryPoints.web]
    address = ":80"
    [entryPoints.web.http.redirections.entryPoint]
      to = "websecure"
      scheme = "https"

  [entryPoints.websecure]
    address = ":443"

また、TLSを介して処理されるトラフィックを自動的にリダイレクトしていることに注意してください。

次に、Traefik apiを構成します。これにより、APIとダッシュボードインターフェイスの両方にアクセスできるようになります。 ダッシュボードはデフォルトで有効になっているため、[api]の見出しだけで十分ですが、当面は明示的になります。

次のコードを追加します。

traefik.toml

...
[api]
  dashboard = true

Webリクエストの保護を完了するには、Let'sEncryptを使用して有効なTLS証明書を生成します。 Traefik v2は、Let's Encryptをすぐにサポートしており、タイプacme証明書リゾルバーを作成することで構成できます。

lets-encryptという名前を使用して、証明書リゾルバーを構成しましょう。

traefik.toml

...
[certificatesResolvers.lets-encrypt.acme]
  email = "your_email@your_domain"
  storage = "acme.json"
  [certificatesResolvers.lets-encrypt.acme.tlsChallenge]

ACME は、Let's Encryptと通信して証明書を管理するために使用されるプロトコルの名前であるため、このセクションはacmeと呼ばれます。 Let's Encryptサービスでは、有効な電子メールアドレスで登録する必要があるため、Traefikにホストの証明書を生成させるには、emailキーを電子メールアドレスに設定します。 次に、Let'sEncryptから受け取る情報をacme.jsonというJSONファイルに保存するように指定します。

acme.tlsChallengeセクションでは、Let'sEncryptが証明書を検証する方法を指定できます。 ポート443を介したチャレンジの一部としてファイルを提供するように構成しています。

最後に、Dockerと連携するようにTraefikを構成する必要があります。

次の構成を追加します。

traefik.toml

...
[providers.docker]
  watch = true
  network = "web"

dockerプロバイダーにより、TraefikはDockerコンテナーの前でプロキシとして機能できます。 webネットワーク上の新しいコンテナ用にwatchにプロバイダーを構成しました。これは、まもなく作成されます。

最終的な構成では、fileプロバイダーを使用します。 Traefik v2では、静的構成と動的構成を混在させて一致させることはできません。 これを回避するには、traefik.tomlを使用して静的構成を定義し、動的構成をtraefik_dynamic.tomlと呼ばれる別のファイルに保持します。 ここでは、fileプロバイダーを使用して、別のファイルから動的構成で読み取る必要があることをTraefikに通知しています。

次のfileプロバイダーを追加します。

traefik.toml

[providers.file]
  filename = "traefik_dynamic.toml"

完成したtraefik.tomlは次のようになります。

traefik.toml

[entryPoints]
  [entryPoints.web]
    address = ":80"
    [entryPoints.web.http.redirections.entryPoint]
      to = "websecure"
      scheme = "https"

  [entryPoints.websecure]
    address = ":443"

[api]
  dashboard = true

[certificatesResolvers.lets-encrypt.acme]
  email = "your_email@your_domain"
  storage = "acme.json"
  [certificatesResolvers.lets-encrypt.acme.tlsChallenge]

[providers.docker]
  watch = true
  network = "web"

[providers.file]
  filename = "traefik_dynamic.toml"

ファイルを保存して閉じます。

それでは、traefik_dynamic.tomlを作成しましょう。

独自のファイルに保持する必要のある動的構成値は、ミドルウェアルーターです。 ダッシュボードをパスワードの背後に配置するには、APIのルーターをカスタマイズし、HTTP基本認証を処理するようにミドルウェアを構成する必要があります。 ミドルウェアを設定することから始めましょう。

ミドルウェアはプロトコルごとに構成され、HTTPを使用しているため、http.middlewaresからチェーンされたセクションとしてミドルウェアを指定します。 次に、後で参照できるようにミドルウェアの名前を示し、次にミドルウェアのタイプ(この場合はbasicAuth)を示します。 ミドルウェアをsimpleAuthと呼びましょう。

traefik_dynamic.tomlという名前の新しいファイルを作成して開きます。

nano traefik_dynamic.toml

次のコードを追加します。 ここに、htpasswdコマンドからの出力を貼り付けます。

traefik_dynamic.toml

[http.middlewares.simpleAuth.basicAuth]
  users = [
    "admin:$apr1$ruca84Hq$mbjdMZBAG.KWn7vfN/SNK/"
  ]

APIのルーターを構成するには、プロトコル名を再度チェーンオフしますが、http.middlewaresを使用する代わりに、http.routersの後にルーターの名前を使用します。 この場合、apiは、[http.routers.api]セクションを使用して構成できる独自の名前付きルーターを提供します。 ホストマッチを使用してruleキーを設定し、websecureを使用するエントリポイント、および [を含むミドルウェアを設定することによって、ダッシュボードで使用する予定のドメインを構成します。 X193X]。

次の構成を追加します。

traefik_dynamic.toml

...
[http.routers.api]
  rule = "Host(`monitor.your_domain`)"
  entrypoints = ["websecure"]
  middlewares = ["simpleAuth"]
  service = "api@internal"
  [http.routers.api.tls]
    certResolver = "lets-encrypt"

webエントリポイントはポート80を処理し、websecureエントリポイントはTLS/SSLにポート443を使用します。 ポート80のすべてのトラフィックをwebsecureエントリポイントに自動的にリダイレクトして、すべての要求に対して安全な接続を強制します。

ここの最後の3行は、 service を構成し、tlsを有効にして、certResolver"lets-encrypt"に構成していることに注意してください。 サービスは、リクエストが最終的に処理される場所を決定するための最終ステップです。 api@internalサービスは、公開するAPIの背後にある組み込みサービスです。 ルーターやミドルウェアと同様に、このファイルでサービスを構成できますが、目的の結果を得るために構成する必要はありません。

完成したtraefik_dynamic.tomlファイルは次のようになります。

traefik_dynamic.toml

[http.middlewares.simpleAuth.basicAuth]
  users = [
    "admin:$apr1$ruca84Hq$mbjdMZBAG.KWn7vfN/SNK/"
  ]

[http.routers.api]
  rule = "Host(`monitor.your_domain`)"
  entrypoints = ["websecure"]
  middlewares = ["simpleAuth"]
  service = "api@internal"
  [http.routers.api.tls]
    certResolver = "lets-encrypt"

ファイルを保存して、エディターを終了します。

これらの構成が整ったら、Traefikを起動します。

ステップ2–Traefikコンテナを実行する

このステップでは、プロキシがコンテナと共有するためのDockerネットワークを作成します。 次に、Traefikダッシュボードにアクセスします。 Dockerネットワークは、DockerComposeを使用して実行されるアプリケーションで使用できるようにするために必要です。

webという名前の新しいDockerネットワークを作成します。

docker network create web

Traefikコンテナが起動したら、このネットワークに追加します。 次に、後でTraefikがプロキシするために、このネットワークにコンテナを追加できます。

次に、Let'sEncrypt情報を保持する空のファイルを作成します。 これをコンテナに共有して、Traefikが使用できるようにします。

touch acme.json

Traefikは、コンテナ内のrootユーザーがこのファイルへの一意の読み取りおよび書き込みアクセス権を持っている場合にのみ、このファイルを使用できます。 これを行うには、acme.jsonの権限をロックダウンして、ファイルの所有者のみが読み取りおよび書き込み権限を持つようにします。

chmod 600 acme.json

ファイルがDockerに渡されると、所有者はコンテナ内のrootユーザーに自動的に変更されます。

最後に、次のコマンドを使用してTraefikコンテナを作成します。

docker run -d \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v $PWD/traefik.toml:/traefik.toml \
  -v $PWD/traefik_dynamic.toml:/traefik_dynamic.toml \
  -v $PWD/acme.json:/acme.json \
  -p 80:80 \
  -p 443:443 \
  --network web \
  --name traefik \
  traefik:v2.2

このコマンドは少し長いです。 分解してみましょう。

-dフラグを使用して、コンテナーをデーモンとしてバックグラウンドで実行します。 次に、docker.sockファイルをコンテナーに共有して、Traefikプロセスがコンテナーへの変更をリッスンできるようにします。 また、traefik.tomltraefik_dynamic.tomlの構成ファイル、およびacme.jsonをコンテナーで共有します。

次に、Dockerホストのポート:80:443をTraefikコンテナー内の同じポートにマップして、TraefikがサーバーへのすべてのHTTPおよびHTTPSトラフィックを受信するようにします。

コンテナのネットワークをwebに設定し、コンテナにtraefikという名前を付けます。

最後に、このコンテナにtraefik:v2.2イメージを使用して、このチュートリアルが記述されているものとは完全に異なるバージョンを実行していないことを保証できます。

DockerイメージのENTRYPOINTは、イメージからコンテナーが作成されるときに常に実行されるコマンドです。 この場合、コマンドはコンテナ内のtraefikバイナリです。 コンテナを起動するときにそのコマンドに追加の引数を渡すことができますが、traefik.tomlファイルですべての設定を構成しました。

コンテナが起動すると、コンテナの状態を確認するためにアクセスできるダッシュボードができました。 このダッシュボードを使用して、Traefikが登録したルーター、サービス、およびミドルウェアを視覚化することもできます。 ブラウザでhttps://monitor.your_domain/dashboard/を指定すると、監視ダッシュボードにアクセスできます(末尾の/が必要です)。

ユーザー名とパスワードの入力を求められます。これらはadminであり、手順1で構成したパスワードです。

ログインすると、Traefikインターフェースが表示されます。

すでにいくつかのルーターとサービスが登録されていることに気付くでしょうが、それらはTraefikとAPI用に作成したルーター構成に付属しているものです。

これでTraefikプロキシが実行され、Dockerと連携して他のコンテナーを監視するように構成されました。 次のステップでは、Traefikがプロキシするためのいくつかのコンテナを開始します。

ステップ3—コンテナをTraefikに登録する

Traefikコンテナを実行すると、その背後でアプリケーションを実行する準備が整います。 Traefikの背後にある次のコンテナを起動しましょう。

  1. 公式WordPress画像を使用したブログ。
  2. 公式管理者イメージを使用するデータベース管理サーバー。

docker-compose.ymlファイルを使用して、DockerComposeでこれらのアプリケーションの両方を管理します。

docker-compose.ymlファイルを作成してエディターで開きます。

nano docker-compose.yml

次の行をファイルに追加して、使用するバージョンとネットワークを指定します。

docker-compose.yml

version: "3"

networks:
  web:
    external: true
  internal:
    external: false

DockerComposeバージョン3は、Composeファイル形式の最新のメジャーバージョンであるため、使用します。

Traefikがアプリケーションを認識するためには、それらが同じネットワークの一部である必要があります。ネットワークを手動で作成したため、webのネットワーク名を指定し、externalを[ X211X]。 次に、別のネットワークを定義して、公開されたコンテナを、Traefikを介して公開しないデータベースコンテナに接続できるようにします。 このネットワークをinternalと呼びます。

次に、各servicesを一度に1つずつ定義します。 blogコンテナーから始めましょう。これは、公式のWordPressイメージに基づいています。 この構成をファイルの最後に追加します。

docker-compose.yml

...

services:
  blog:
    image: wordpress:4.9.8-apache
    environment:
      WORDPRESS_DB_PASSWORD:
    labels:
      - traefik.http.routers.blog.rule=Host(`blog.your_domain`)
      - traefik.http.routers.blog.tls=true
      - traefik.http.routers.blog.tls.certresolver=lets-encrypt
      - traefik.port=80
    networks:
      - internal
      - web
    depends_on:
      - mysql

environmentキーを使用すると、コンテナー内に設定される環境変数を指定できます。 WORDPRESS_DB_PASSWORDの値を設定しないことで、Docker Composeにシェルから値を取得し、コンテナーを作成するときにそれを渡すように指示します。 コンテナを起動する前に、シェルでこの環境変数を定義します。 このようにして、パスワードを構成ファイルにハードコーディングする必要はありません。

labelsセクションでは、Traefikの構成値を指定します。 Dockerラベルはそれ自体では何もしませんが、Traefikはこれらを読み取るため、コンテナーの処理方法を認識しています。 これらの各ラベルの機能は次のとおりです。

  • traefik.http.routers.adminer.rule=Host(``` blog.your_domain ```) creates a new ルーター for your container and then specifies the routing rule used to determine if a request matches this container.
  • traefik.routers.custom_name.tls=trueは、このルーターがTLSを使用する必要があることを指定します。
  • traefik.routers.custom_name.tls.certResolver=lets-encryptは、lets-encryptと呼ばれる、前に作成した証明書リゾルバーを使用して、このルートの証明書を取得する必要があることを指定します。
  • traefik.portは、トラフィックをこのコンテナにルーティングするためにTraefikが使用する必要がある公開ポートを指定します。

この構成では、blog.your_domainのドメインを持つポート80または443でDockerホストに送信されるすべてのトラフィックは、blogコンテナーにルーティングされます。

このコンテナを2つの異なるネットワークに割り当てて、Traefikがwebネットワーク経由でコンテナを見つけ、internalネットワーク経由でデータベースコンテナと通信できるようにします。

最後に、depends_onキーは、依存関係が実行された後にこのコンテナーを開始する必要があることをDockerComposeに通知します。 WordPressを実行するにはデータベースが必要なため、blogコンテナーを開始する前に、mysqlコンテナーを実行する必要があります。

次に、MySQLサービスを構成します。

docker-compose.yml

services:
...
  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD:
    networks:
      - internal
    labels:
      - traefik.enable=false

このコンテナには、公式のMySQL5.7イメージを使用しています。 値のないenvironmentアイテムをもう一度使用していることに気付くでしょう。 WordPressコンテナがMySQLと通信できるようにするには、MYSQL_ROOT_PASSWORD変数とWORDPRESS_DB_PASSWORD変数を同じ値に設定する必要があります。 mysqlコンテナをTraefikまたは外部に公開したくないので、このコンテナをinternalネットワークに割り当てるだけです。 TraefikはDockerソケットにアクセスできるため、プロセスはデフォルトでmysqlコンテナーのルーターを公開します。したがって、ラベルtraefik.enable=falseを追加して、Traefikがこのコンテナーを公開しないように指定します。 。

最後に、Adminerコンテナを定義します。

docker-compose.yml

services:
...
  adminer:
    image: adminer:4.6.3-standalone
    labels:
      - traefik.http.routers.adminer.rule=Host(`db-admin.your_domain`)
      - traefik.http.routers.adminer.tls=true
      - traefik.http.routers.adminer.tls.certresolver=lets-encrypt
      - traefik.port=8080
    networks:
      - internal
      - web
    depends_on:
      - mysql

このコンテナは、公式のAdminerイメージに基づいています。 このコンテナーのnetworkおよびdepends_on構成は、blogコンテナーに使用しているものと完全に一致します。

traefik.http.routers.adminer.rule=Host(``` db-admin.your_domain ```)は、要求されたホストを調べるようにTraefikに指示します。 db-admin.your_domainのパターンと一致する場合、Traefikはトラフィックをポート8080を介してadminerコンテナにルーティングします。

完成したdocker-compose.ymlファイルは次のようになります。

docker-compose.yml

version: "3"

networks:
  web:
    external: true
  internal:
    external: false

services:
  blog:
    image: wordpress:4.9.8-apache
    environment:
      WORDPRESS_DB_PASSWORD:
    labels:
      - traefik.http.routers.blog.rule=Host(`blog.your_domain`)
      - traefik.http.routers.blog.tls=true
      - traefik.http.routers.blog.tls.certresolver=lets-encrypt
      - traefik.port=80
    networks:
      - internal
      - web
    depends_on:
      - mysql

  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD:
    networks:
      - internal
    labels:
      - traefik.enable=false

  adminer:
    image: adminer:4.6.3-standalone
    labels:
    labels:
      - traefik.http.routers.adminer.rule=Host(`db-admin.your_domain`)
      - traefik.http.routers.adminer.tls=true
      - traefik.http.routers.adminer.tls.certresolver=lets-encrypt
      - traefik.port=8080
    networks:
      - internal
      - web
    depends_on:
      - mysql

ファイルを保存して、テキストエディタを終了します。

次に、WORDPRESS_DB_PASSWORD変数とMYSQL_ROOT_PASSWORD変数の値をシェルに設定します。

export WORDPRESS_DB_PASSWORD=secure_database_password
export MYSQL_ROOT_PASSWORD=secure_database_password

secure_database_passwordを目的のデータベースパスワードに置き換えます。 WORDPRESS_DB_PASSWORDMYSQL_ROOT_PASSWORDの両方に同じパスワードを使用することを忘れないでください。

これらの変数を設定した状態で、docker-composeを使用してコンテナーを実行します。

docker-compose up -d

次に、Traefik管理ダッシュボードが表示されているのを確認します。

ルーターセクションを調べると、TLSで構成されたadminerおよびblog用のルーターが見つかります。

blog.your_domainに移動し、your_domainをドメインに置き換えます。 TLS接続にリダイレクトされ、WordPressのセットアップを完了することができます。

次に、ブラウザでdb-admin.your_domainにアクセスし、ドメインをyour_domainに置き換えて、Adminerにアクセスします。 mysqlコンテナは外界に公開されていませんが、adminerコンテナは、mysqlを使用して共有するinternalDockerネットワークを介してアクセスできます。 ]ホスト名としてのコンテナ名。

管理者ログイン画面で、ユーザー名rootと入力し、サーバーmysqlと入力し、MYSQL_ROOT_PASSWORDに設定した値を入力します。 ] Passwordの場合。 データベースは空のままにします。 次に、ログインを押します。

ログインすると、Adminerユーザーインターフェイスが表示されます。

現在、両方のサイトが機能しており、monitor.your_domainのダッシュボードを使用してアプリケーションを監視できます。

結論

このチュートリアルでは、Dockerコンテナー内の他のアプリケーションにリクエストをプロキシするようにTraefikv2を構成しました。

アプリケーションコンテナレベルでのTraefikの宣言型構成により、より多くのサービスを簡単に構成できます。TraefikはDockerソケットファイルを介して変更にすぐに気付くため、プロキシトラフィックに新しいアプリケーションを追加するときにtraefikコンテナを再起動する必要はありません。監視しています。

Traefik v2でできることの詳細については、公式のTraefikドキュメントにアクセスしてください。