这篇文章主要围绕使用Docker在Linux上托管ASP.NETCore应用程序和docker.netcore3linux展开,旨在为您提供一份详细的参考资料。我们将全面介绍使用Docker在Linu
这篇文章主要围绕使用 Docker 在 Linux 上托管 ASP.NET Core 应用程序和docker .net core 3 linux展开,旨在为您提供一份详细的参考资料。我们将全面介绍使用 Docker 在 Linux 上托管 ASP.NET Core 应用程序的优缺点,解答docker .net core 3 linux的相关问题,同时也会为您带来500内部服务器错误Docker托管ASP.Net MVC Web应用程序(已解决)、Asp.Net Core 发布到 Docker(Linux Centos 虚拟机,使用Dockerfile)、asp.net core 发布到linux下Docker、ASP.NET Core 实战:使用 Docker 容器化部署 ASP.NET Core + MySQL + Nginx的实用方法。
本文目录一览:- 使用 Docker 在 Linux 上托管 ASP.NET Core 应用程序(docker .net core 3 linux)
- 500内部服务器错误Docker托管ASP.Net MVC Web应用程序(已解决)
- Asp.Net Core 发布到 Docker(Linux Centos 虚拟机,使用Dockerfile)
- asp.net core 发布到linux下Docker
- ASP.NET Core 实战:使用 Docker 容器化部署 ASP.NET Core + MySQL + Nginx
使用 Docker 在 Linux 上托管 ASP.NET Core 应用程序(docker .net core 3 linux)
说在前面#
在阅读本文之前,您必须对 Docker 的中涉及的基本概念以及常见命令有一定了解,本文侧重实战,不会对相关概念详述。
同时请确保您本地开发机器已完成如下安装:
- Docker 18.06 或更高版本的 Docker 客户端
- .NET Core SDK 2.2 或更高版本
- Visual Studio Code 代码编辑器,以及 C# 语法插件 1.17.1 或更高版本
注:本文实验环境是 Ubuntu 18.04 LTS。如果您的机器是 Window,也可以把 Docker 装在虚拟机或服务器上。
创建演示项目#
开始之前要先准备一个需要 Docker 容器化的 ASP.NET Core 应用程序,用于下面的操作演示。这里我用 .NET Core CLI 快速搭建一个全新的 Web API 项目。
启动 VS Code,打开集成终端,输入如下命令:
dotnet new webapi -o TodoApi
code -r TodoApi
以上便创建了一个名为TodoApi
的 Web API 样板项目。
打开集成终端,输入dotnet run
命令编译运行程序,然后打开浏览器跳转到 URL http://localhost:5000/api/values
,如正常返回如下 JSON 数据,说明应用程序本地成功运行。
["value1","value2"]
现在让我们更进一步,在 Docker 中构建并运行该应用程序。
创建 Dockerfile 文件#
Dockerfile 是一个文本文件,其用来定义单个容器的内容和启动行为,按顺序包含构建镜像所需的所有指令。Docker 会通过读取 Dockerfile 中的指令自动构建镜像。
在项目TodoApi
根目录中,创建一个名为Dockerfile
的文件,并粘贴以下内容:
FROM microsoft/dotnet:2.2-sdk AS build-env
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore
# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out
# Build runtime image
FROM microsoft/dotnet:2.2-aspnetcore-runtime
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "TodoApi.dll"]
FROM
指令必须放在第一位,用于初始化镜像,为后面的指令设置基础镜像。
WORKDIR
指令为其他指令设置工作目录,如果不存在,则会创建该目录。
COPY
指令会从源路径复制新文件或目录,并将它们添加到路径目标容器的文件系统中。
RUN
指令可以在当前镜像之上的新 层 中执行任何命令并提交结果,生成的已提交镜像将用于 Dockerfile 中的下一步。
ENTRYPOINT
指令支持以可执行文件的形式运行容器。
有关 Dockerfile 中指令用法的更多信息请参阅 Dockerfile reference。
同时,为了避免构建项目中的一些调试生成文件,可以在项目文件夹中新增.dockerignore
文件,并粘贴如下内容:
bin\
obj\
构建应用容器镜像#
在项目TodoApi
根目录中,打开集成终端,执行如下命令构建容器镜像:
docker build -t todoapi .
-t
参数用来指定镜像的名字及标签,通常是name:tag
或者name
格式。本例todoapi
便是我们给镜像起的名字,没有设置标签即使用默认标签latest
。
如命令执行成功,终端会有类似如下输出:
$ docker build -t todoapi .
Sending build context to Docker daemon 1.137MB
Step 1/10 : FROM microsoft/dotnet:2.2-sdk AS build-env
2.2-sdk: Pulling from microsoft/dotnet
e79bb959ec00: Pull complete
d4b7902036fe: Pull complete
1b2a72d4e030: Pull complete
d54db43011fd: Pull complete
b3ae1535ac68: Pull complete
f04cf82b07ad: Pull complete
6f91a9d92092: Pull complete
Digest: sha256:c443ff79311dde76cb1acf625ae47581da45aad4fd66f84ab6ebf418016cc008
Status: Downloaded newer image for microsoft/dotnet:2.2-sdk
---> e268893be733
Step 2/10 : WORKDIR /app
---> Running in c7f62130f331
Removing intermediate container c7f62130f331
---> e8b6a73d3d84
Step 3/10 : COPY *.csproj ./
---> cfa03afa6003
Step 4/10 : RUN dotnet restore
---> Running in d96a9b89e4a9
Restore completed in 924.67 ms for /app/TodoApi.csproj.
Removing intermediate container d96a9b89e4a9
---> 14d5d32d40b6
Step 5/10 : COPY . ./
---> b1242ea0b0b8
Step 6/10 : RUN dotnet publish -c Release -o out
---> Running in 37c8eb07c86e
Microsoft (R) Build Engine version 16.0.450+ga8dc7f1d34 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
Restore completed in 663.74 ms for /app/TodoApi.csproj.
TodoApi -> /app/bin/Release/netcoreapp2.2/TodoApi.dll
TodoApi -> /app/out/
Removing intermediate container 37c8eb07c86e
---> 6238f4c1cf07
Step 7/10 : FROM microsoft/dotnet:2.2-aspnetcore-runtime
2.2-aspnetcore-runtime: Pulling from microsoft/dotnet
27833a3ba0a5: Pull complete
25dbf7dc93e5: Pull complete
0ed9cb15d3b8: Pull complete
874ea13b7488: Pull complete
Digest: sha256:ffd756d34bb0f976ba5586f6c88597765405af8014ae51b34811992b46ba40e8
Status: Downloaded newer image for microsoft/dotnet:2.2-aspnetcore-runtime
---> cb2dd04458bc
Step 8/10 : WORKDIR /app
---> Running in b0a3826d346b
Removing intermediate container b0a3826d346b
---> 4218db4cc2f5
Step 9/10 : COPY --from=build-env /app/out .
---> 765168aa2c7a
Step 10/10 : ENTRYPOINT ["dotnet", "TodoApi.dll"]
---> Running in f93bcaf5591f
Removing intermediate container f93bcaf5591f
---> 046226f5e9cb
Successfully built 046226f5e9cb
Successfully tagged todoapi:latest
如果您的机器是第一次构建,速度可能会有些慢,因为要从 Docker Hub 上拉取应用依赖的
dotnet-sdk
和aspnetcore-runtime
基础镜像。
构建完成后,我们可以通过docker images
命令确认本地镜像仓库是否存在我们构建的镜像todoapi
。
REPOSITORY TAG IMAGE ID CREATED SIZE
todoapi latest c92a82f0efaa 19 hours ago 260MB
microsoft/dotnet 2.2-sdk 5e09f77009fa 26 hours ago 1.74GB
microsoft/dotnet 2.2-aspnetcore-runtime 08ed21b5758c 26 hours ago 260MB
运行应用容器#
容器镜像构建完成后,就可以使用docker run
命令运行容器了,有关该命令参数的更多信息请参阅 Reference - docker run 。
开发环境下,通常会通过docker run --rm -it
命令运行应用容器,具体命令如下:
docker run --rm -it -p 5000:80 todoapi
-it
参数表示以交互模式运行容器并为容器重新分配一个伪输入终端,方便查看输出调试程序。
--rm
参数表示将会在容器退出后自动删除当前容器,开发模式下常用参数。
-p
参数表示会将本地计算机上的5000
端口映射到容器中的默认80
端口,端口映射的关系为host:container
。todoapi
便是我们要启动的本地镜像名称。
如命令执行成功,终端会有类似如下输出:
$ docker run -it --rm -p 5000:80 todoapi
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
No XML encryptor configured. Key {1a78d899-738b-4aea-a7d6-777302933f38} may be persisted to storage in unencrypted form.
Hosting environment: Production
Content root path: /app
Now listening on: http://[::]:80
Application started. Press Ctrl+C to shut down.
生产环境下,通常会通过docker run -d
命令运行应用容器,具体命令如下:
docker run -d --restart=always --name myapp -p 5000:80 todoapi
-d
参数表示会将容器作为服务启动,不需要终端交互。--name
参数用来指定容器名称,本例指定容器名称为myapp
。--restart
是一个面向生产环境的参数,用来指定容器非正常退出时的重启策略,本例always
表示始终重新启动容器,其他可选策略请参考 Restart policies (--restart)。
如命令执行成功,终端会有类似如下输出:
$ docker run -d --restart=always --name myapp -p 5000:80 todoapi
e3d747d9d2b4cd14b2acb24f81bea9312f89c4eb689dba5f6559950c91db1600
容器启动后,在 Web 浏览器中再次访问http://localhost:5000/api/values
,应该会和本地测试一样返回如下 JSON 数据:
["value1","value2"]
至此,我们的 ASP.NET Core 应用就成功运行在 Docker 容器中了。
多容器应用部署#
目前我们创建的演示项目TodoApi
过于简单,真实的生产项目肯定会涉及更多其他的依赖。例如:关系数据库 Mysql、文档数据库 MongoDB、分布式缓存 Redis、消息队列 RabbitMQ 等各种服务。
还有就是,生产环境我们一般不会将 ASP.NET Core 应用程序的宿主服务器 Kestrel 直接暴露给用户,通常是在前面加一个反向代理服务 Nginx。
这些依赖服务还要像传统部署方式那样,一个一个单独配置部署吗?不用的,因为它们本身也是可以被容器化的,所以我们只要考虑如何把各个相互依赖的容器联系到一起,这就涉及到容器编排,而 Docker Compose 正是用来解决这一问题的,最终可以实现多容器应用的一键部署。
Docker Compose 是一个用于定义和运行多容器的 Docker 工具。其使用
YAML
文件来配置应用程序的服务,最终您只要使用一个命令就可以从配置中创建并启动所有服务。
安装 Docker Compose#
Linux 系统下的安装过程大致分为以下几步:
Step1:运行如下命令下载 Compose 最新稳定版本,截止发稿前最新版本为1.24.0
。
sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
Step2:对下载完成的二进制程序添加可执行权限。
sudo chmod +x /usr/local/bin/docker-compose
Step3:测试安装是否成功。
$ docker-compose --version
docker-compose version 1.24.0, build 0aa59064
若您在安装过程中遇到问题,或是其他系统安装请参阅 Install Docker Compose。
改造演示项目#
现在来改造一下我们的演示项目TodoApi
,添加 Redis 分布式缓存、使用 Nginx 做反向代理,准备构建一个具如下图所示架构的多容器应用。
在TodoApi
项目根目录下,打开集成终端,输入如下命令新增 Redis 依赖包。
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis --version 2.2.0
修改应用启动配置文件Startup.cs
中的ConfigureServices
方法:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = Configuration.GetConnectionString("Redis");
});
services.AddHttpContextAccessor();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
在TodoApi
项目Controllers
目录下新建控制器HelloController
,具体代码如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
namespace TodoApi.Controllers
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
namespace TodoApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class HelloController : ControllerBase
{
private readonly IDistributedCache _distributedCache;
private readonly IHttpContextAccessor _httpContextAccessor;
public HelloController(
IDistributedCache distributedCache,
IHttpContextAccessor httpContextAccessor)
{
_distributedCache = distributedCache;
_httpContextAccessor = httpContextAccessor;
}
[HttpGet]
public ActionResult<string> Get()
{
var connection = _httpContextAccessor.HttpContext.Connection;
var ipv4 = connection.LocalIpAddress.MapToIPv4().ToString();
var message = $"Hello from Docker Container:{ipv4}";
return message;
}
[HttpGet("{name}")]
public ActionResult<string> Get(string name)
{
var defaultKey = $"hello:{name}";
_distributedCache.SetString(defaultKey, $"Hello {name} form Redis");
var message = _distributedCache.GetString(defaultKey);
return message;
}
}
}
以上控制器,提供了两个接口/api/hello
和/api/hello/{name}
,分别用来测试 Nginx 负载均衡和 Redis 的联通性。
创建 docker-compose.yml#
准备工作就绪,下面我们就可以使用 Docker Compose 来编排容器。
同样是在TodoApi
项目根目录中,创建一个名为docker-compose.yml
的文件,并粘贴以下内容:
version: "3.7"
services:
myproject-todoapi-1:
container_name: my-todoapi-1
build:
context: .
dockerfile: Dockerfile
restart: always
ports:
- "5001:80"
volumes:
- ./appsettings.json:/app/appsettings.json
myproject-todoapi-2:
container_name: my-todoapi-2
build:
context: .
dockerfile: Dockerfile
restart: always
ports:
- "5002:80"
volumes:
- ./appsettings.json:/app/appsettings.json
myproject-todoapi-3:
container_name: my-todoapi-3
build:
context: .
dockerfile: Dockerfile
restart: always
ports:
- "5003:80"
volumes:
- ./appsettings.json:/app/appsettings.json
myproject-nginx:
container_name: my-nginx
image: nginx
restart: always
ports:
- "80:80"
volumes:
- ./conf/nginx.conf:/etc/nginx/conf.d/default.conf
myproject-redis:
container_name: my-redis
image: redis
restart: always
ports:
- "6379:80"
volumes:
- ./conf/redis.conf:/etc/redis/redis.conf
其中version
用来指定 Compose 文件版本号,3.7
是目前最新版本,具体哪些版本对应哪些特定的 Docker 引擎版本请参阅 Compose file versions and upgrading。
Compose 中强化了服务的概念,简单地理解就是, 服务是一种用于生产环境的容器。一个多容器 Docker 应用由若干个服务组成,如上文件即定义了 5 个服务:
- 3 个应用服务
myproject-todoapi-1
、myproject-todoapi-2
和myproject-todoapi-3
- 1 个 Nginx 服务
myproject-reverse-proxy
- 1 个 Redis 服务
myproject-redis
以上 5 个服务的配置参数相差无几、也很简单,我就不展开叙述,不清楚的可以参阅 Compose file reference。
这里只讲一个配置参数volumes
:
我们知道,容器中的文件在宿主机上存在形式复杂,修改文件需要先通过如下命令进入容器后操作。
docker exec -it <CONTAINER ID/NAMES> /bin/bash
容器一旦删除,其内部配置以及产生的数据也会丢失。
为了解决这些问题,Docker 引入了数据卷 volumes 机制。即 Compose 中 volumes 参数用来将宿主机的某个目录或文件映射挂载到 Docker 容器内部的对应的目录或文件,通常被用来灵活挂载配置文件或持久化容器产生的数据。
PS:自己动手编写
docker-compose.yml
的时候,可以尝试实验更多场景。比如:新增一个 MySQL 依赖服务、把容器内产生的数据持久化到宿主机等等。
创建相关配置文件#
接下来,需要根据如上docker-compose.yml
文件中涉及的volumes
配置创建三个配置文件。要知道,它们最终是需要被注入到 Docker 容器中的。
首先,在TodoApi
项目根目录中,创建三个应用服务myproject-todoapi-*
需要的程序配置文件appsettings.json
,具体内容如下:
"ConnectionStrings": {
"Redis": "myproject-redis:6379,password=todoapi@2019"
},
以上配置,指定了 Redis 服务myproject-redis
的连接字符串,其中myproject-redis
可以看到是 Redis 服务的服务名称,当该配置文件注入到 Docker 容器中后,会自动解析为容器内部 IP,同时考虑到 Redis 服务的安全性,为其指定了密码,即password=todoapi@2019
。
然后,在TodoApi
项目根目录中创建一个子目录conf
,用来存放 Nginx 和 Redis 的配置文件。
mkdir conf && cd conf
先来创建 Redis 服务myproject-redis
的配置文件。
可以通过如下命令,下载一个 Redis 官方提供的标准配置文件redis.conf
:
wget http://download.redis.io/redis-stable/redis.conf
然后打开下载后的redis.conf
文件,找到SECURITY
节点,根据如上应用服务的 Redis 连接字符串信息,启用并改下密码:
requirepass todoapi@2019
再来创建 Nginx 服务myproject-nginx
的配置文件。
在conf
目录中,创建一个名为nginx.conf
的配置文件,并粘贴如下内容:
upstream todoapi {
server myproject-todoapi-1:80;
server myproject-todoapi-2:80;
server myproject-todoapi-3:80;
}
server {
listen 80;
location / {
proxy_pass http://todoapi;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
以上配置,是一个 Nginx 中具备负载均衡的代理配置,其默认采用轮循策略将请求转发给 Docker 服务myproject-todoapi-1
、myproject-todoapi-2
和myproject-todoapi-3
。
运行并测试多容器应用#
经过以上几个小节,容器编排的过程就完成了,接下来就可以直接定义并启动我们创建的多容器应用实例了。
切换到docker-compose.yml
文件所在的目录,也就是TodoApi
项目的根目录,执行如下命令:
docker-compose up -d
如命令执行成功,终端最后会有类似如下输出:
......
Creating my-todoapi-1 ... done
Creating my-redis ... done
Creating my-todoapi-3 ... done
Creating my-nginx ... done
Creating my-todoapi-2 ... done
至此,我们的多容器应用就已经在运行了,可以通过docker-compose ps
命令来确认下。
$ docker-compose ps
Name Command State Ports
--------------------------------------------------------------------------------------
my-nginx nginx -g daemon off; Up 0.0.0.0:80->80/tcp
my-redis docker-entrypoint.sh redis ... Up 6379/tcp, 0.0.0.0:6379->80/tcp
my-todoapi-1 dotnet TodoApi.dll Up 0.0.0.0:5001->80/tcp
my-todoapi-2 dotnet TodoApi.dll Up 0.0.0.0:5002->80/tcp
my-todoapi-3 dotnet TodoApi.dll Up 0.0.0.0:5003->80/tcp
可以通过连续三次请求/api/hello
接口测试应用的负载均衡。
curl http://localhost/api/hello
curl http://localhost/api/hello
curl http://localhost/api/hello
// Output:
Hello from Docker Container:172.30.0.2
Hello from Docker Container:172.30.0.4
Hello from Docker Container:172.30.0.5
三个应用服务分别部署在不同容器中,所以理论上来讲,他们的容器内部 IP 也是不同的,所以/api/hello
接口每次输出信息不会相同。
请求/api/hello/{name}
接口测试 Redis 服务连通性。
curl http://localhost/api/hello/esofar
// Output:
Hello esofar form Redis
小结#
本文从零构建了一个 ASP.NET Core 应用,并通过 Docker 部署,然后由浅入深,引入 Docker Compose 演示了多容器应用的部署过程。通过本文的实战您可以更深入地了解 Docker。本文涉及的代码已托管到以下地址,您在实验过程中遇到问题可以参考。
https://github.com/esofar/dockerize-aspnetcore-samples
Docker 命令附录#
$ docker --help
Usage: docker [OPTIONS] COMMAND
A self-sufficient runtime for containers
Options:
--config string Location of client config files (default "/root/.docker")
-D, --debug Enable debug mode
-H, --host list Daemon socket(s) to connect to
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/root/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit
Management Commands:
builder Manage builds
config Manage Docker configs
container Manage containers
engine Manage the docker engine
image Manage images
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
secret Manage Docker secrets
service Manage services
stack Manage Docker stacks
swarm Manage Swarm
system Manage Docker
trust Manage trust on Docker images
volume Manage volumes
Commands:
attach Attach local standard input, output, and error streams to a running container
build Build an image from a Dockerfile
commit Create a new image from a container''s changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container''s filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container''s filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes
Docker Compose 命令附录#
$ docker-compose --help
Define and run multi-container applications with Docker.
Usage:
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
docker-compose -h|--help
Options:
-f, --file FILE Specify an alternate compose file
(default: docker-compose.yml)
-p, --project-name NAME Specify an alternate project name
(default: directory name)
--verbose Show more output
--log-level LEVEL Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
--no-ansi Do not print ANSI control characters
-v, --version Print version and exit
-H, --host HOST Daemon socket to connect to
--tls Use TLS; implied by --tlsverify
--tlscacert CA_PATH Trust certs signed only by this CA
--tlscert CLIENT_CERT_PATH Path to TLS certificate file
--tlskey TLS_KEY_PATH Path to TLS key file
--tlsverify Use TLS and verify the remote
--skip-hostname-check Don''t check the daemon''s hostname against the
name specified in the client certificate
--project-directory PATH Specify an alternate working directory
(default: the path of the Compose file)
--compatibility If set, Compose will attempt to convert keys
in v3 files to their non-Swarm equivalent
Commands:
build Build or rebuild services
bundle Generate a Docker bundle from the Compose file
config Validate and view the Compose file
create Create services
down Stop and remove containers, networks, images, and volumes
events Receive real time events from containers
exec Execute a command in a running container
help Get help on a command
images List images
kill Kill containers
logs View output from containers
pause Pause services
port Print the public port for a port binding
ps List containers
pull Pull service images
push Push service images
restart Restart services
rm Remove stopped containers
run Run a one-off command
scale Set number of containers for a service
start Start services
stop Stop services
top Display the running processes
unpause Unpause services
up Create and start containers
version Show the Docker-Compose version information
相关阅读#
- ASP.NET Core Docker Sample
- Dockerize a .NET Core application
- Best practices for writing Dockerfiles
- Fun With Docker-Compose Using .NET Core And NGINX
- ASP.NET Core 2.2: implementando Load Balancing com Nginx, Docker e Docker Compose
转自:https://www.cnblogs.com/esofar/p/10694319.html?from=timeline
500内部服务器错误Docker托管ASP.Net MVC Web应用程序(已解决)
您需要从网站的应用程序池中查找网站正在运行的身份(默认情况下,这是应用程序池身份),然后授予该正确的权限。通常是IIS_IUSRS,您可以尝试以下步骤解决问题:
右键单击文件夹->转到安全选项卡->单击编辑->单击添加->单击高级 ->立即查找->授予IIS_IUSRS权限(完全控制)->单击“确定”->单击“确定”-> 在allow->中单击“完全控制”,然后单击“确定”。
注意:如果上述操作不起作用,请尝试向NETWORK,NETWORK SERVICE用户授予相同的权限
Asp.Net Core 发布到 Docker(Linux Centos 虚拟机,使用Dockerfile)
实践一下 Asp.Net Core (基于.net core 2.2)部署到Docker
一、准备工作:
1. 使用VirtualBox创建一个Centos系统的虚拟机,并安装docker和vim
2. 配置好端口(如下图,后面需要使用)
3. 准备一个网站发布包(我采用的默认的Asp.Net Core MVC),windows发布时的配置(也可以在linux上进行发布),将发布包放入linux虚拟机(我的路径是:/root/Root/DefaultHttp/publish)
4. 测试一下发布包是否正常(可选,需要在linux安装.net core sdk,如果版本较低,需要使用sudo yum update命令更新)
dotnet publish/DefaultHttp.dll
如图显示,是正常的
5. 创建Dockfile文件(路径:/root/Root/DefaultHttp/,即和publish文件夹同级),并把下面的代码放入文件中。
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 workdir /app EXPOSE 5000 # 一般情况下必须开放 EXPOSE 80 # 如果使用https,记得打开443端口,但是一般不用 #EXPOSE 443 copY publish/ /app ENTRYPOINT ["dotnet","DefaultHttp.dll"]
至此,准备工作完成。
二、创建镜像
1. 切换至 /root/Root/DefaultHttp/
cd Root/DefaultHttp/
2. 执行以下命令,使用Dockerfile创建镜像(镜像名称为:firsthttp/default)
docker build -t firsthttp/default .
3. 执行docker images 命令查看生成的镜像
三、运行容器
1. 执行以下命令,运行容器(linux虚拟机的8010端口映射docker容器的80端口)
docker run -d -p 8010:80 -p 5000:5000 --name first firsthttp/default
2. 查看运行中的容器
docker ps
3. 查看容器日志
docker logs -f ef5d4c3870f1
为什么需要这个步骤?
查看容器运行的日志信息,防止发生错误,也可以知道容器开放的端口(这里是80,映射到linux虚拟机是8010端口,映射到主机也是8010端口(第一步的准备工作中有))
4. 在linux虚拟机查看结果,执行以下命令
curl http://localhost:8010
5. 在主机访问
至此,部署完成。
四、删除容器和镜像
#删除容器 docker rm 容器ID #删除镜像 docker rmi firsthttp/default
五、总结:
1. Docker容器对外发布的是80端口(需要使用docker logs命令查看)
2. 执行docker run 命令运行容器时,可以添加 -v 参数,映射指定的数据卷(这里是publish文件夹),下次更新程序时,会自动更新到docker,只需要重启docker即可(docker restart firsthttp/default)
asp.net core 发布到linux下Docker
1.linux Docker 安装
内核升级:https://www.cnblogs.com/zksfyz/p/7919425.html
安装: https://www.runoob.com/docker/centos-docker-install.html
2.发布asp.net core
网上大部分教程都是采用编写Dockerfile文件的方法,然后打包程序到一个新镜像中,而我不用这种方法。我这里直接通过docker运行本地程序。
1、拉取镜像文件
拉取微软官方aspcore runtime镜像文件,执行“docker pull microsoft/dotnet:aspnetcore-runtime”,注意这里使用的是带“aspnetcore-runtime”TAG的镜像,这个镜像才有runtime。如果需要拉取特定的版本,比如2.1版本,可以用“docker pull microsoft/dotnet:2.1-aspnetcore-runtime”这样的写法,更多说明见https://hub.docker.com/r/microsoft/dotnet
拉取成功后通过“docker images”来查看
2、发布程序
注意部署模式改为“框架依赖”,目标运行时改为“可移植”。发布成功后将文件拷贝到服务器上,比如我放在“/home/www”下面。
最后执行“docker run -d -p 5000:80 -v /home/www:/app --workdir /app microsoft/dotnet:aspnetcore-runtime dotnet /app/MyServer.dll”,服务器就能跑起来了!
-d参数表示容器在后台运行,我们不需要进入到容器。
-p参数表示端口映射,“-p 5000:80”表示将容器的80端口映射到本地5000端口。
-v参数表示目录映射,将服务器的/home/www目录挂到容器的/app目录。
--workdir参数表示容器中服务程序的工作路径,也就是我们映射的/app目录。
“microsoft/dotnet:aspnetcore-runtime”表示要运行的镜像。
最后的"dotnet /app/MyServer.dll"表示容器启动后要执行的命令,这里也就是启动服务程序了,MyServer.dll是我的主程序文件名,你们修改为自己的即可。
最后可以通过"docker ps"来查看正在运行中的容器。
ASP.NET Core 实战:使用 Docker 容器化部署 ASP.NET Core + MySQL + Nginx
一、前言
在之前的文章(ASP.NET Core 实战:Linux 小白的 .NET Core 部署之路)中,我介绍了如何在 Linux 环境中安装 .NET Core SDK /.NET Core Runtime、Nginx、MySQL,以及如何将我们的 ASP.NET Core MVC 程序部署到 Linux 上,同时,使用 supervisor 守护程序守护我们的 .NET Core 程序。如果,你有看过那篇文章,并且和我一样是个 Linux 小白用户的话,可能第一感觉就是,把 .NET Core 项目部署在 IIS 上也挺好。
将 .NET Core 项目部署到 Linux 上如此复杂,就没有简单的部署方式吗?
你好,有的,Docker 了解一下~~~
PS:这里的示例代码还是采用之前的毕业设计项目,在这篇文章发布的时候,我已经在程序的仓库中添加了对于 Docker 的支持,你可以下载下来,自己尝试一下,毕竟,实践出真知。
代码仓储:https://github.com/Lanesra712/Danvic.PSU
二、Step by Step
1、安装 Docker & Docker Compose
在代码交付的过程中,偶尔会遇到这样的问题,在本地测试是好的,但是部署到测试环境、生产环境时就出这样那样的问题,同时,因为本地与测试环境、生产环境之间存在差异,我们可能无法在本地复现这些问题,那么,有没有一种工具可以很好的解决这一问题呢?随着历史的车轮不断前行,容器技术诞生了。
Docker,作为最近几年兴起的一种虚拟化容器技术,他可以将我们的运行程序与操作系统做一个隔离,例如这里我们需要运行 .NET Core 程序,我们不再需要关心底层的操作系统是什么,不需要在每台需要需要运行程序的机器上安装程序运行的各种依赖,我们可以通过程序打包成镜像的方式,将应用程序和该程序的依赖全部置于一个镜像文件中,这时,只要别的机器上有安装 Docker,就可以通过我们打包的这个镜像来运行这个程序。
1.1、卸载 Docker
在安装 Docker 之前,我们应该确定当前的机器上是否已经安装好了 Docker,为了防止与现在安装的 Docker CE 发生冲突,这里我们先卸载掉以前版本的 Docker,如果你确定你的机器上并没有安装 Docker 的话此步可以跳过。
在 Linux 中可以使用 \ 加 Enter 在输入很长很长的语句时进行换行,这里和后面的命令都是采用这样的方式。
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
1.2、添加 yum 源
在安装 Docker CE 的方式上,我是采用将 Docker CE 的源添加到 yum 源中,之后我们就可以直接使用 yum install 安装 Docker CE,整个的安装过程如下。
# 安装工具包从而可以让我们在 yum 中添加别的仓储源
sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
# 设置 docker ce 的稳定库地址
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# 安装 docker ce
sudo yum install docker-ce docker-ce-cli containerd.io
当我们安装好 Docker 之后,我们就可以使用 docker 命令验证我们是否在机器上成功安装了 Docker,同时,也可以使用 docker --version 命令查看我们安装的 Docker CE 版本。
1.3、设置开机自启
当 Docker 已经在我们的机器上安装完成后,我们就可以将 Docker 设置成机器的自启服务,这样,如果出现服务器重启的情况下,我们的 Docker 也可以随服务器的重启自动启动 Docker 服务。
# 启动 Docker 服务并允许开机自启
sudo systemctl start docker
# 查看当前 dokcer 的运行情况
sudo systemctl status docker
1.4、Hello World
就像我们在学习一门新的语言时,运行的第一句代码,几乎都是打印出 Hello World,而在 Docker Hub 中,也有这么一个镜像,在无数的 Docker 教程中,安装完 Docker 后,第一件事就是拉取这个镜像文件,“告诉” Docker,我来了。
Docker Hub 是存放镜像的仓库,里面包含了许多的镜像文件,因为服务器在国外的原因,下载的速度可能不理想,像国内的阿里云、腾讯云也有提供对于 Docker 镜像的加速器服务,你可以按需使用,当然,你也可以创建属于你的私有镜像仓库。
docker run hello-world
docker run 命令,它会在我们的本地镜像库中先寻找这个镜像,然后运行。如果在本地没有找到的话,则会自动使用 docker pull 从 Docker Hub 中寻找,能找到的话,则会自动下载到本地,然后运行,找不到的话,这条命令也就运行失败了。
1.5、安装 Docker Compose
在实际的项目开发中,我们可能会有多个应用镜像,例如在本篇文章的示例中,为了在 Docker 中运行我们的程序,我们需要三个镜像:应用程序自身镜像、MySQL Server 镜像、以及 Nginx 镜像,为了将我们的程序启动起来,我们需要手敲各个容器的启动参数,环境变量,容器命名,指定不同容器的链接参数等等一系列的操作,又多又烦,可能某一步操作失败后程序就无法正常运行。而当我们使用了 Docker Compose 之后,我们就可以把这些命令一次性写在 docker-compose.yml 配置文件中,以后每次启动我们的应用程序时,只需要通过 docker compose 命令就可以自动帮我们完成这些操作。
# 从 github 下载 docker compose 二进制文件
sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 对下载的二进制文件应用可执行权限
sudo chmod +x /usr/local/bin/docker-compose
# 查看 docker compose 版本
docker-compose --version
2、构建程序镜像
当我们在服务器上安装好 docker 和 docker compose 之后,就可以开始构建我们的程序镜像了。首先我们需要对我们的运行程序添加对于 Docker 的支持。你可以自己手动在 MVC 项目中添加 Dockerfile 文件,或是通过右键添加 Docker 支持。
Dockerfile 就像一个执行的清单,它告诉 Docker,我们这个镜像在构建和运行时需要按照什么样的命令运行。打开 VS 为我们自动创建的 Dockerfile,可以看到清晰的分成了四块的内容。
我们知道,.NET Core 程序的运行需要依赖于 .NET Core Runtime(CoreCLR),因此,为了使我们的程序可以运行起来,我们需要从 hub 中拉取 runtime ,并在 此基础上构建我们的应用镜像。同时,为了避免因为基础的环境的不同造成对程序的影响,这里的 Runtime 需要同程序开发时的 .NET Core SDK 版本保持一致,所以这里我使用的是 .NET Core 2.1 Runtime。
一个镜像中包含了应用程序及其所有的依赖,与虚拟机不同的是,容器中的每个镜像最终是共享了宿主机的操作系统资源,容器作为用户空间中的独立进程运行在主机操作系统上。
PS: 图片版权归属于微软的技术文档,如有侵权,请联系我删除,源文件地址:什么是 Docker?
镜像可以看成一个个小型的 “虚拟主机”,这里我们在镜像中创建了一个 /app 路径作为我们程序在镜像中的工作目录,同时,将 80 端口暴露给 Docker,从而可以使我们在镜像外面通过端口访问到当前镜像中的运行的程序。
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
因为我们的应用是一个多层架构的单体应用,最终的 MVC 项目依赖于解决方案中的各个类库以及我们从 Nuget 中下载的各种第三方组件,在部署时,需要将这些组件打包成 dll 引用。所以,这里我们需要使用 .NET Core SDK 中包含的 .NET Core CLI 进行还原和构建。
就像在下面的代码中,我们在镜像的内部创建了一个 /src 的路径,将当前解决方案下的类库都复制到这个目录下,之后通过 dotnet restore 命令还原我们的主程序所依赖的各个组件。当我们还原好依赖的组件后,就可以使用 dotnet build 命令生成 Release 版本的 dll 文件,同时输出到之前创建的 /app 路径下。
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY ["PSU.Site/PSU.Site.csproj", "PSU.Site/"]
COPY ["03_Logic/PSU.Domain/PSU.Domain.csproj", "03_Logic/PSU.Domain/"]
COPY ["03_Logic/PSU.Repository/PSU.Repository.csproj", "03_Logic/PSU.Repository/"]
COPY ["01_Entity/PSU.Entity/PSU.Entity.csproj", "01_Entity/PSU.Entity/"]
COPY ["02_Infrastructure/PSU.Utility/PSU.Utility.csproj", "02_Infrastructure/PSU.Utility/"]
COPY ["04_Rule/PSU.Model/PSU.Model.csproj", "04_Rule/PSU.Model/"]
COPY ["02_Infrastructure/PSU.EFCore/PSU.EFCore.csproj", "02_Infrastructure/PSU.EFCore/"]
COPY ["04_Rule/PSU.IService/PSU.IService.csproj", "04_Rule/PSU.IService/"]
COPY ["Controllers.PSU/Controllers.PSU.csproj", "Controllers.PSU/"]
RUN dotnet restore "PSU.Site/PSU.Site.csproj"
COPY . .
WORKDIR "/src/PSU.Site"
RUN dotnet build "PSU.Site.csproj" -c Release -o /app
上面一步可以看成我们在使用 VS 生成 Release 版本的解决方案,当生成没有出错之后,我们就可以进行程序的发布。
FROM build AS publish
RUN dotnet publish "PSU.Site.csproj" -c Release -o /app
当已经生成发布文件之后,按照我们平时部署在 Windows 上的过程,这时就可以通过 IIS 部署运行了,因此,构建我们应用镜像的最后一步就是通过 dotnet 命令执行我们的程序。
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "PSU.Site.dll"]
似乎到这一步构建程序镜像就结束了,按照这样流程做的话,就需要我们将整个的解决方案上传到服务器上了,可是,很多时候,我们仅仅是把我们在本地发布好的项目上传到服务器上,这与我们现在的构建流程具有很大的不同,所以这里我们来修改 Dockerfile 文件,从而符合我们的发布流程。
从上面分析 Dockerfile 的过程中不难看出,在服务器上构建镜像的第二步、第三步就是我们现在在开发环境中手动完成的部分,所以这里,我们只需要对这部分进行删除即可,修改后的 Dockerfile 如下。
FROM microsoft/dotnet:2.1-aspnetcore-runtime
WORKDIR /app
COPY . /app
EXPOSE 80
ENTRYPOINT ["dotnet","PSU.Site.dll"]
在修改后的 Dockerfile 中,可以看到,我们删去了 build 和 release 的过程,选择直接将我们 Dockerfile 路径下的文件拷贝到镜像中的 /app 路径下,然后直接执行 dotnet 命令,运行我们的程序。
为了确保 Dockerfile 与发布后的文件处于同一路径下,这里我们需要使用 VS 修改 Dockerfile 的属性值,确保会复制到输出的目录下,这里选择如果较新则复制即可。
3、编写 docker-compose.yml
当我们构建好应用的镜像,对于 Nginx 和 MySQL 我们完全可以从 hub 中拉取下来,再执行一些配置即可。所以,我们现在就可以编写 docker compose 文件,来定义我们的应用镜像运行时需要包含的依赖以及每个镜像的启动顺序。
右键选中 MVC 项目,添加一个 docker-compose.yml 文件,同样的,需要修改该文件的属性,以便于该文件可以复制到输出目录下。注意,这里的文件名和上文的 Dockerfile 都是特定的,你不能做任何的修改。如果你的电脑上已经安装了 Docker for Windows,你也可以使用 VS,右键添加,选中容器业务流程协调程序支持自动对 docker compose 进行配置。
在 yml 文件中,我定义了三个镜像:psu.site、docker.mysql、docker.nginx。三个镜像的定义中有许多相同的地方,都设置了自动重启(restart),以及都处于同一个桥接网络下(psu-net)从而达到镜像间的通信。
docker.mysql 是 MySQL 的镜像,我们通过环境变量 MYSQL_ROOT_PASSWORD 设置了 MySQL 的数据库连接密码,并通过挂载卷的方式将镜像中的数据库文件持久化到我们的服务器本地路径中。同时,将镜像的 3306 端口映射到服务器的 3306 端口上。
psu.site 则是我们的程序镜像,采用位于 /usr/wwwroot/psu/ 路径下的 Dockerfile 文件进行构建的,因为主程序的运行需要依赖于数据库,所以这里采用 depends_on 属性,使我们的应用镜像依赖于 docker.mysql 镜像,即,在 docker.mysql 启动后才会启动应用镜像。
docker.nginx 则是我们的 nginx 镜像,这里将镜像中的 80 端口和 443 端口都映射到服务器 IP 上,因为我们需要配置 Nginx 从而监听我们的程序,所以通过挂载卷的方式,将本地的 nginx.conf 配置文件用配置映射到镜像中。同时,因为我们在构建应用镜像的 Dockerfile 文件时,对外暴露了 80 端口,所以这里就可以通过 links 属性进行监听(如果构建时未暴露端口,你可以在 docker compose 文件中通过 Expose 属性暴露镜像中的端口)。
Nginx 的配置文件如下,这里特别需要注意文件的格式,缩进,一点小错误都可能导致镜像无法正常运行。如果你和我一样将 nginx.conf 放到程序运行路径下的,别忘了修改文件的属性。
server {
listen 80;
location / {
proxy_pass http://psu.site;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
}
}
一个完整的 docker compose 文件如下,包含了三个镜像以及一个桥接网络。
version: ''3.7''
services:
docker.mysql:
image: mysql
ports:
- "3306:3306"
restart: always
environment:
- MYSQL_ROOT_PASSWORD=123456@sql
volumes:
- /usr/mysql:/var/lib/mysql
networks:
- psu-net
psu.site:
build: /usr/wwwroot/psu/
restart: always
depends_on:
- docker.mysql
networks:
- psu-net
docker.nginx:
image: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
links:
- psu.site
networks:
- psu-net
networks:
psu-net:
driver: bridge
这里需要注意,所有有用到镜像间的通信的地方,我们都需要使用镜像名进行指代,例如上面的 nginx 的配置文件中,我们需要将监听的地址改为镜像名称,以及,我们需要修改程序的数据库访问字符串的服务器地址,修改后的数据库连接字符串如下所示。
"ConnectionStrings": {
"SQLConnection": "server=docker.mysql;database=PSU.Site;user=root;password=123456@sql;port=3306;persistsecurityinfo=True;"
}
4、发布部署程序
当我们构建好 docker compose 文件后就可以把整个文件上传到服务器上进行构建 docker 镜像了。这里我将所有的部署文件放在服务器的 /usr/wwwroot/psu/ 路径下,这时我们就可以通过 docker compose 命令进行镜像构建。
定位到部署文件在的位置,我们可以直接使用下面的命令进行镜像的(重新)构建,启动,并链接一个服务相关的容器,整个过程都会在后台运行,如果你希望看到整个过程的话,你可以去掉 -d 参数。
# 执行镜像构建,启动
docker-compose up -d
当 up 命令执行完成后,我们就可以通过 ps 命令查看正在运行的容器,若有的容器并没有运行起来,则可以使用 logs 查看容器的运行日志从而进行排错。
# 查看所有正在运行的容器
docker-compose ps
# 显示容器运行日志
docker-compose logs
三、总结
本章主要是介绍了如何通过 docker 容器,完整的部署一个可实际使用的 .NET Core 的单体应用,相比于之前通过 Linux 部署 .NET Core 应用,可以看到整个步骤少了很多,也简单很多。文中涉及到了一些 docker 的命令,如果你之前并没有接触过 docker 的话,可能需要你进一步的了解。当我们将程序打包成一个镜像之后,你完全可以将镜像上传到私有镜像仓库中,或是直接打包成镜像的压缩文件,这样,当需要切换部署环境时,只需要获取到这个镜像之后即可快速完成部署,相比之前,极大的方便了我们的工作。
我们今天的关于使用 Docker 在 Linux 上托管 ASP.NET Core 应用程序和docker .net core 3 linux的分享已经告一段落,感谢您的关注,如果您想了解更多关于500内部服务器错误Docker托管ASP.Net MVC Web应用程序(已解决)、Asp.Net Core 发布到 Docker(Linux Centos 虚拟机,使用Dockerfile)、asp.net core 发布到linux下Docker、ASP.NET Core 实战:使用 Docker 容器化部署 ASP.NET Core + MySQL + Nginx的相关信息,请在本站查询。
本文标签: