web-dev-qa-db-ja.com

Docker ComposeでMSSQLを待つ方法は?

MSSQLに依存するservice(ASP.NET Core Webアプリケーション)があります。サービスはDocker composeを使用して調整されます。Dockercomposeが最初にデータベースを起動し、サービスが実行される前にデータベースがreadyになるまで待機します。そのため、docker-compose.ymlを次のように定義しています。

version: '3.7'

services:

  sql.data:
    container_name: db_service
    image: Microsoft/mssql-server-linux:2017-latest
    healthcheck:
      test: ["CMD", "/opt/mssql-tools/bin/sqlcmd", "-S", "http://localhost:1433", "-U", "sa", "-P", "Pass_Word", "-Q", "SELECT 1", "||", "exit 1"]

  my_service:
    container_name: my_service_container
    image: ${DOCKER_REGISTRY-}my_service
    build:
      context: .
      dockerfile: MyService/Dockerfile
    depends_on:
      - sql.data

このヘルスチェックにより、Docker composeはデータベースサービスの準備が整うまで待機せず、直後にmy_serviceを開始し、予想どおり、my_serviceがデータベースへの接続に失敗します。ログの一部は次のとおりです。

Recreating db_service ... done
Recreating my_service_container ... done
Attaching to db_service, my_service_container 
my_service_container | info: ...Context[0]
my_service_container |       Migrating database associated with context Context
my_service_container | info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
my_service_container |       Entity Framework Core 3.1.1 initialized 'Context' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: MigrationsAssembly=MyService
my_service_container | fail: Context[0]
my_service_container |       An error occurred while migrating the database used on context Context
my_service_container | Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 40 - Could not open a connection to SQL Server)
...
exception details
...
my_service_container | ClientConnectionId:00000000-0000-0000-0000-000000000000
my_service_container exited with code 0
db_service | 2020-03-05 05:45:51.82 Server      Microsoft SQL Server 2017 (RTM-CU13) (KB4466404) - 14.0.3048.4 (X64)
        Nov 30 2018 12:57:58
        Copyright (C) 2017 Microsoft Corporation
        Developer Edition (64-bit) on Linux (Ubuntu 16.04.5 LTS)
2020-03-05 05:45:51.82 Server      UTC adjustment: 0:00
2020-03-05 05:45:51.82 Server      (c) Microsoft Corporation.
2020-03-05 05:45:51.82 Server      All rights reserved.
2020-03-05 05:45:51.82 Server      Server process ID is 4120.
2020-03-05 05:45:51.82 Server      Logging SQL Server messages in file '/var/opt/mssql/log/errorlog'.
2020-03-05 05:45:51.82 Server      Registry startup parameters:
         -d /var/opt/mssql/data/master.mdf
         -l /var/opt/mssql/data/mastlog.ldf
         -e /var/opt/mssql/log/errorlog

ログに示されているように、Docker Composeは最初にDBを起動しますが、サービスが実行される前に準備が整うまで待機しません。

私はhealthcheckに別の構文を試しました、例えば:

test: /opt/mssql-tools/bin/sqlcmd -S http://localhost:1433 -U sa -P ${SA_PASSWORD} -Q "SELECT 1" || exit 1

しかし、どちらも期待どおりに機能しませんでした。

以下の情報源をオンラインで確認しましたが、どちらを使用しても問題を解決できませんでした。

この機能はversion 3.7でもサポートされていますか? この混乱するコメントのため


質問

MSSQLサービスが開始するのをどのくらい待つことができるかについての考えはありますか?

3
Hamed

多くのさまざまなシナリオを検索して試した後、次のcomposerファイルを使用して待機を追加できました。これはasp.netコアソリューション用です。重要なのは、エントリポイントを上書きする必要があることです。 dockerfileで指定します。また、 "wait-for-it.sh" LFをCRLFではなく行末として保存する必要があります。そうしないと、ファイルが見つからないというエラーが発生します。

Dockerfileには次のものが必要です(ここからダウンロードしてください: https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh 、必ず確認してくださいファイルを保存します):

COPY ./wait-for-it.sh /wait-for-it.sh
RUN chmod +x wait-for-it.sh

docker-compose.yml

version: '3.7'

services:

  vc-db:
    image: mcr.Microsoft.com/mssql/server:latest
    ports:
      - "${DOCKER_SQL_PORT:-1433}:1433"
    expose:  
      - 1433  
    environment: 
      - ACCEPT_EULA=Y
      - MSSQL_PID=Express
      - SA_PASSWORD=v!rto_Labs!
    networks:
      - virto

  vc-platform-web:
    image: virtocommerce/platform:${DOCKER_TAG:-latest}
    ports:
      - "${DOCKER_PLATFORM_PORT:-8090}:80"
    environment:
      - ASPNETCORE_URLS=http://+
    depends_on:
      - vc-db
    entrypoint: ["/wait-for-it.sh", "vc-db:1433", "-t", "120", "--", "dotnet", "VirtoCommerce.Platform.Web.dll"]
    networks:
      - virto
3
Woland

depends_onを使用すると、docker-composeはベースサービスをより優先して起動し、サービスの開始を待ちません。

特定のサービス(ポート)を待ってから別のサービスを実行するのに役立つ、いくつかの便利な外部プログラムがあります。

vishnubob/wait-for-it は、特定のポートが準備ができるまで実行フローをブロックするそれらの1つです。
別の良い選択は eficode/wait-for で、これは既にdocker-composeのために準備されています。

使用例(eficode/wait-for docsによる)

version: '2'

services:
  db:
    image: postgres:9.4

  backend:
    build: backend
    # Blocks execution flow util db:5432 is ready (Or you can use localhost instead)
    command: sh -c './wait-for db:5432 -- npm start'
    depends_on:
      - db

-更新-

PostgreSQLのようなデータベースに依存するPythonアプリケーションがあるとします。また、アプリケーションは次のコマンドで実行されます:python app.py
Official Docker Document が言ったように、vishnubob/wait-for-itをイメージに(app.pyなどの他のプロジェクトファイルの中に)挿入します

次に、この行をdocker-compose.ymlに挿入します。

version: "3"
services:
  web:
    build: .
    ports:
      - "80:8000"
    depends_on:
      - "db"
    # This command waits until `db:5432` respond (5432 is default PostgreSQL port)
    # then runs our application by this command: `python app.py`
    command: ["./wait-for-it.sh", "db:5432", "--", "python", "app.py"]
  db:
    image: postgres

注:画像ファイル内のDockerfileにこのコマンドを含めることを忘れないでください:

# Copy wait-for-it.sh into our image
COPY wait-for-it.sh wait-for-it.sh
# Make it executable, in Linux
RUN chmod +x wait-for-it.sh
2
user12958509

2つの個別のdockerfileを作成します(例):

  1. Mssql.Dockerfile
  2. App.Dockerfile

Docker-compose.yml内でシーケンスを設定する

Mssql.Dockerfile

FROM mcr.Microsoft.com/mssql/server AS base

ENV ACCEPT_EULA=Y
ENV SA_PASSWORD=Password123

COPY . .
COPY ["Db/Scripts/*", "Db/Scripts/"]
VOLUME ./Db:/var/opt/mssql/data

HEALTHCHECK --interval=10s --timeout=5s --start-period=10s --retries=10 \
    CMD /opt/mssql-tools/bin/sqlcmd -S . -U sa -P Password123 -i Db/Scripts/SetupDb.sql || exit 1

App.Dockerfile:

    FROM mcr.Microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
    WORKDIR /app
    EXPOSE 80
    EXPOSE 443

    FROM mcr.Microsoft.com/dotnet/core/sdk:3.1-buster AS build
    WORKDIR /src
    COPY ["AspNetCoreWebApplication/AspNetCoreWebApplication.csproj", "AspNetCoreWebApplication/"]
    COPY ["WebApp.Data.EF/WebApp.Data.EF.csproj", "WebApp.Data.EF/"]
    COPY ["WebApp.Service/WebApp.Service.csproj", "WebApp.Service/"]

    RUN dotnet restore "AspNetCoreWebApplication/AspNetCoreWebApplication.csproj"
    COPY . .
    WORKDIR "/src/AspNetCoreWebApplication"
    RUN dotnet build "AspNetCoreWebApplication.csproj" -c Release -o /app/build
    FROM build AS publish
    RUN dotnet publish "AspNetCoreWebApplication.csproj" -c Release -o /app/publish

    FROM base AS final
    WORKDIR /app
    COPY --from=publish /app/publish .
    ENTRYPOINT ["dotnet", "AspNetCoreWebApplication.dll"]

Docker-compose.yml:

version: '3.7'

services:
    api:
        image: aspnetcore/mentoring_api
        container_name: mentoring_api
        build:
            context: .
            dockerfile: App.Dockerfile
        ports:
            - 8081:80
        expose: 
            - 8081
        environment:
            ASPNETCORE_ENVIRONMENT: Development
        depends_on:
            - sqlserver
    sqlserver:
        image: aspnetcore/mentoring_db
        container_name: mentoring_db
        build:
            context: .
            dockerfile: Mssql.Dockerfile
        ports:
            - "1433:1433"
        expose: 
            - 1433
        environment:
            - ACCEPT_EULA=Y
            - SA_PASSWORD=Password123
        volumes:
            - ./Db:/var/opt/mssql/data

注:接続文字列は次のようになります:"Server=sqlserver;Database=Northwind;Trusted_Connection=False;User Id=sa;Password=Password123;MultipleActiveResultSets=true"

1
AllmanTool

アプリのコンテナーで起動される簡単なスクリプトを記述できます。たとえば、sleep N(NはDBの起動に必要な時間)を使用して遅延を設定するか、またはuntilサイクルを使用して試すことができますDBに接続し、可能な場合はアプリを起動できます。

これは完璧な解決策ではないことはわかっていますが、同様の問題があったときに役に立ちました