Ham*_*med 20 c# sql-server docker docker-compose asp.net-core
我有一个依赖于 MSSQL的服务(一个 ASP.NET Core Web 应用程序)。这些服务是使用 Docker compose 编排的,我希望 docker compose在运行我的服务之前首先启动数据库并等待它准备就绪。为此,我将其定义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
Run Code Online (Sandbox Code Playgroud)
通过这种健康检查,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
Run Code Online (Sandbox Code Playgroud)
如日志中所示,docker compose 首先启动数据库,但在运行我的服务之前不会等待它准备就绪。
我为 尝试了不同的语法healthcheck
,例如:
test: /opt/mssql-tools/bin/sqlcmd -S http://localhost:1433 -U sa -P ${SA_PASSWORD} -Q "SELECT 1" || exit 1
Run Code Online (Sandbox Code Playgroud)
但两者都没有按预期工作。
我已经在线检查了以下来源,但使用两者都无法解决问题:
甚至支持此功能version 3.7
吗?因为这个令人困惑的评论
关于如何最好地等待 MSSQL 服务启动的任何想法?
小智 9
当您使用 时depends_on
,docker-compose 只会以更高的优先级启动您的基本服务,而不会等待启动服务。
有一些有用的外部程序可以帮助您等待特定服务(端口),然后运行另一个服务。
vishnubob/wait-for-it是其中之一,它会阻止执行流,直到您的特定端口准备就绪。
另一个不错的选择是eficode/wait-for,它已经为docker -compose 做好了准备。
示例用法(根据 eficode/wait-for 文档)
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
Run Code Online (Sandbox Code Playgroud)
- 更新 -
假设您有一个依赖于 PostgreSQL 等数据库的 Python 应用程序,并且您的应用程序将使用以下命令运行:python app.py
正如Docker 官方文档所说,放入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
Run Code Online (Sandbox Code Playgroud)
注意:不要忘记将此命令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
Run Code Online (Sandbox Code Playgroud)
在搜索并尝试了许多不同的场景后,我能够使用以下 Composer 文件添加等待。这是asp.net
核心解决方案。关键是entrypoint
如果在dockerfile
. 此外,您需要确保将“wait-for-it.sh” LF 保存为行尾而不是 CRLF,否则您将收到file not found
.
本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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
我认为你最初的尝试实际上并不遥远。使用运行状况检查似乎是最合适的途径,因此我将继续使用该方法,但是您将希望condition
利用depends_on
. 这样,您可以使用service_healthy
条件,该条件将等待您的 SQL Server 运行状况检查报告运行状况良好。
请参阅 Docker 网站上的这篇文章,其中提到了这一点: https ://docs.docker.com/compose/startup-order/
你的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:
condition: service_healthy
Run Code Online (Sandbox Code Playgroud)
您还可以利用healthcheck
如下所示的选项和稍微简洁的语法:
version: '3.7'
services:
sql.data:
container_name: db_service
image: microsoft/mssql-server-linux:2017-latest
healthcheck:
test: /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "Pass_word" -Q "SELECT 1" -b -o /dev/null
interval: 10s
timeout: 3s
retries: 10
start_period: 10s
my_service:
container_name: my_service_container
image: ${DOCKER_REGISTRY-}my_service
build:
context: .
dockerfile: MyService/Dockerfile
depends_on:
sql.data:
condition: service_healthy
Run Code Online (Sandbox Code Playgroud)
创建两个单独的 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
Run Code Online (Sandbox Code Playgroud)
应用程序.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"]
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
注意:
连接字符串将如下所示:"Server=sqlserver;Database=Northwind;Trusted_Connection=False;User Id=sa;Password=Password123;MultipleActiveResultSets=true"
这是一个完整的例子
\nversion: "3.8"\n\nservices:\n ms-db-server:\n image: mcr.microsoft.com/mssql/server\n environment: \n - SA_PASSWORD=P@ssw0rd\n - ACCEPT_EULA=Y\n volumes:\n - ./data/db/mssql/scripts:/scripts/\n ports:\n - "1433:1433"\n #entrypoint: /bin/bash\n command:\n - /bin/bash\n - -c\n - |\n /opt/mssql/bin/sqlservr &\n pid=$$!\n\n echo "Waiting for MS SQL to be available \xe2\x8f\xb3"\n /opt/mssql-tools/bin/sqlcmd -l 30 -S localhost -h-1 -V1 -U sa -P $$SA_PASSWORD -Q "SET NOCOUNT ON SELECT \\"YAY WE ARE UP\\" , @@servername"\n is_up=$$?\n while [ $$is_up -ne 0 ] ; do\n echo -e $$(date)\n /opt/mssql-tools/bin/sqlcmd -l 30 -S localhost -h-1 -V1 -U sa -P $$SA_PASSWORD -Q "SET NOCOUNT ON SELECT \\"YAY WE ARE UP\\" , @@servername"\n is_up=$$?\n sleep 5\n done\n\n for foo in /scripts/*.sql\n do /opt/mssql-tools/bin/sqlcmd -U sa -P $$SA_PASSWORD -l 30 -e -i $$foo\n done\n echo "All scripts have been executed. Waiting for MS SQL(pid $$pid) to terminate."\n\n wait $$pid\n\n tempo:\n image: grafana/tempo:latest\n command: ["-config.file=/etc/tempo.yaml"]\n volumes:\n - ./etc/tempo-local.yaml:/etc/tempo.yaml\n - ./data/tempo-data:/tmp/tempo\n ports:\n - "14268" # jaeger ingest, Jaeger - Thrift HTTP\n - "14250" # Jaeger - GRPC\n - "55680" # OpenTelemetry\n - "3100" # tempo\n - "6831/udp" # Jaeger - Thrift Compact\n - "6832/udp" # Jaeger - Thrift Binary \n\n tempo-query:\n image: grafana/tempo-query:latest\n command: ["--grpc-storage-plugin.configuration-file=/etc/tempo-query.yaml"]\n volumes:\n - ./etc/tempo-query.yaml:/etc/tempo-query.yaml\n ports:\n - "16686:16686" # jaeger-ui\n depends_on:\n - tempo\n\n loki:\n image: grafana/loki:2.1.0\n command: -config.file=/etc/loki/loki-local.yaml\n ports:\n - "3101:3100" # loki needs to be exposed so it receives logs\n environment:\n - JAEGER_AGENT_HOST=tempo\n - JAEGER_ENDPOINT=http://tempo:14268/api/traces # send traces to Tempo\n - JAEGER_SAMPLER_TYPE=const\n - JAEGER_SAMPLER_PARAM=1\n volumes:\n - ./etc/loki-local.yaml:/etc/loki/loki-local.yaml\n - ./data/loki-data:/tmp/loki\n\n nodejs-otel-tempo-api:\n build: .\n command: \'./wait-for.sh ms-db-server:1433 -- node ./dist/server.js\'\n ports:\n - "5555:5555"\n environment:\n - OTEL_EXPORTER_JAEGER_ENDPOINT=http://tempo:14268/api/traces\n - OTEL_SERVICE_NAME=nodejs-opentelemetry-tempo\n - LOG_FILE_NAME=/app/logs/nodejs-opentelemetry-tempo.log\n - DB_USER=sa\n - DB_PASS=P@ssw0rd\n - DB_SERVER=ms-db-server\n - DB_NAME=OtelTempo\n volumes:\n - ./data/logs:/app/logs\n - ./etc/wait-for.sh:/app/bin/wait-for.sh #https://github.com/eficode/wait-for\n depends_on:\n - ms-db-server\n - tempo-query\n\n promtail:\n image: grafana/promtail:master-ee9c629\n command: -config.file=/etc/promtail/promtail-local.yaml\n volumes:\n - ./etc/promtail-local.yaml:/etc/promtail/promtail-local.yaml\n - ./data/logs:/app/logs\n depends_on:\n - nodejs-otel-tempo-api\n - loki\n\n prometheus:\n image: prom/prometheus:latest\n volumes:\n - ./etc/prometheus.yaml:/etc/prometheus.yaml\n entrypoint:\n - /bin/prometheus\n - --config.file=/etc/prometheus.yaml\n ports:\n - "9090:9090"\n depends_on:\n - nodejs-otel-tempo-api\n\n grafana:\n image: grafana/grafana:7.4.0-ubuntu\n volumes:\n - ./data/grafana-data/datasources:/etc/grafana/provisioning/datasources\n - ./data/grafana-data/dashboards-provisioning:/etc/grafana/provisioning/dashboards\n - ./data/grafana-data/dashboards:/var/lib/grafana/dashboards\n environment:\n - GF_AUTH_ANONYMOUS_ENABLED=true\n - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin\n - GF_AUTH_DISABLE_LOGIN_FORM=true\n ports:\n - "3000:3000"\n depends_on:\n - prometheus\n - tempo-query\n - loki\n
Run Code Online (Sandbox Code Playgroud)\n
归档时间: |
|
查看次数: |
10489 次 |
最近记录: |