我在业余时间开发了一款自己的独立产品:升讯威在线客服与营销系统。陆陆续续开发了几年,从一开始的偶有用户尝试,到如今线上环境和私有化部署均有了越来越多的稳定用户,在这个过程中,我也积累了不少如何开发运营一款独立产品的经验。

在这几年时间中,有一些客户始终在用我的客服系统,昨天给一位客户更新系统,看到更新记录,第一次给他版本是 2021 年 9 月,一转眼,快 4 年了……

这些的长期客户还有好几家,另外还有很多客户,是从 博客园 看到的文章找到的我,包括最初的种子客户也是,也很感谢 博客园


最初我开发的在线客服系统版本,只能运行在 Windows + SQL Server 上,后来在用户的建议和帮助下,逐渐拓展到了 Linux + MySQL、宝塔面板,最后拓展到了 Docker,在这篇文章中,我主要讲 Docker 打包发布的过程和一些注意事项。

可能有些朋友会疑问,打包 Docker 镜像应该很容器吧?其实这说的也没错,如何仅仅只是打包一个能跑的镜像,那几行命令就可以,但是如果你要提供一个商业级的产品,那方方面面的细节都需要考虑周全。

我记得最初我做的镜像,docker run 之后,还得 exec 到容器内部去修改配置文件,再重启服务才能使用,这个使用门槛就一下变得很高,用户要用也很麻烦。

现在我通过环境变量,直接在 docker run 的时候把参数带进去,完全实现了一键运行,一分钟系统上线,有兴趣的朋友可以看我的 Docker Hub 主页:升讯威在线客服与营销系统


.NET 程序打包到docker 镜像的注意事项

1. 选择合适的基础镜像

  • .NET Core / .NET 5+:如果你使用的是 .NET Core 或 .NET 5+,你应该选择官方的 .NET 镜像作为基础镜像。例如,mcr.microsoft.com/dotnet/aspnet:5.0 适用于 ASP.NET Core 应用,mcr.microsoft.com/dotnet/runtime:5.0 适用于运行时。
  • 分层镜像:为了减小镜像体积,可以使用分层镜像(multi-stage build)。例如,首先使用包含 SDK 的镜像进行构建,最后只复制构建好的产物到运行时镜像。
# 使用 .NET SDK 镜像进行构建
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /app
COPY . .
RUN dotnet publish -c Release -o out # 使用 .NET Runtime 镜像运行
FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app
COPY --from=build /app/out .
ENTRYPOINT ["dotnet", "MyApp.dll"]

2. 优化 Dockerfile

  • COPY 指令:尽量减少 Docker 镜像层数。将 .csproj 和其他依赖文件单独复制,然后运行 dotnet restore,而不是将整个项目一起复制。这可以避免每次构建时重新下载依赖。
  • 构建缓存:利用 Docker 构建缓存,使得在代码不发生改变时,Docker 可以复用先前的层,减少构建时间。
# 先复制项目文件并还原依赖
COPY *.csproj ./
RUN dotnet restore # 然后复制所有源代码
COPY . ./

3. 确保运行时环境的正确性

  • 环境变量:如果应用程序依赖于环境变量(如数据库连接字符串、API 密钥等),可以在 Dockerfile 或 Docker 运行命令中设置这些环境变量。
ENV ASPNETCORE_ENVIRONMENT=Production
ENV ConnectionStrings__MyDb="Server=db;Database=mydb;User=sa;Password=Password123"
  • 文件权限:确保复制到 Docker 镜像中的文件有正确的权限。例如,使用 RUN chmod 调整权限,避免容器内的文件权限问题。

4. 配置文件

  • appsettings.json:如果你的应用使用配置文件,可以选择将配置文件放入 Docker 镜像中,或者将配置文件放在外部,并通过 Docker 挂载来管理配置。

5. 网络和数据库连接

  • 连接字符串:如果应用连接到数据库或其他外部服务,最好避免将敏感数据(如连接字符串)硬编码在代码中。可以使用环境变量或 Docker secrets 进行管理。

6. 日志记录

  • Docker 容器中通常没有 UI,所以要确保将日志输出到标准输出(stdout)或标准错误(stderr)。这能确保日志能被 Docker 捕获并显示出来,便于调试。
// 在 .NET 中,通常会配置日志输出
builder.Logging.AddConsole();

7. 容器内存限制

  • 如果你的应用程序需要较多内存,考虑在 Docker 容器中设置合适的内存限制,避免应用因资源不足而崩溃。
docker run -m 512m myapp

8. 清理无用文件

  • 在 Dockerfile 中使用 dotnet publish 生成发布文件时,可以去除不必要的文件,如测试、源码文件,减少镜像大小。
  • 使用 dotnet publish --self-contained 创建自包含的发布包,以便不依赖 Docker 中的 .NET SDK。

9. 安全性

  • 使用 Docker 多阶段构建时,确保最终镜像只包含运行时所需的文件。
  • 不要在镜像中包含开发工具、调试符号、源码或其他非生产所需的内容。

10. 测试镜像

  • 打包完 Docker 镜像后,确保在本地或 staging 环境进行全面的测试,检查应用在容器中的运行情况,包括性能、连接、日志和异常处理。

11. 推送和部署

  • 在推送镜像到 Docker 仓库时,考虑使用合适的标签(例如,latest, v1.0.0, production)来管理版本。
  • 使用 Kubernetes 或 Docker Swarm 等容器编排工具来管理和部署你的容器。

示例 Dockerfile

# 1. 基础镜像
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build # 2. 设置工作目录并复制文件
WORKDIR /app
COPY *.csproj ./
RUN dotnet restore # 3. 复制源代码并构建发布包
COPY . ./
RUN dotnet publish -c Release -o out # 4. 使用运行时镜像
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS runtime
WORKDIR /app
COPY --from=build /app/out ./ # 5. 设置启动命令
ENTRYPOINT ["dotnet", "MyApp.dll"]

如何让你的独立产品用上 Docker 环境变量

Docker环境变量是 Docker 容器化应用中一种重要的配置方式。它们可以帮助在容器启动时为应用提供必要的参数或配置,而不需要修改容器内部的代码或配置文件。Docker 环境变量使得容器可以更加灵活和动态化,尤其在不同的部署环境中尤为重要。

1. 什么是 Docker 环境变量?

Docker 环境变量(Environment Variables)是操作系统层面上用于存储配置信息的变量。在 Docker 容器中,环境变量通常用于存储应用的配置信息、凭证、API 密钥、数据库连接字符串等。它们可以在容器启动时传递,并可以在运行时访问和修改。

2. 为什么使用环境变量?

  • 灵活性:可以根据不同的运行环境提供不同的值,无需修改容器镜像。
  • 安全性:可以避免硬编码敏感信息(如密码、API 密钥等),提升安全性。
  • 配置管理:通过环境变量可以在不修改容器内容的情况下,动态调整容器行为。

3. 如何在 Docker 中使用环境变量?

Docker 提供了几种设置和使用环境变量的方式:

3.1 使用 -e--env 参数设置环境变量

在使用 docker run 启动容器时,可以通过 -e 参数来设置环境变量。例如:

docker run -e MY_ENV_VAR=value my_image

这样会在容器中设置一个名为 MY_ENV_VAR 的环境变量,值为 value

3.2 使用 .env 文件

为了方便管理多个环境变量,可以使用 .env 文件。在 .env 文件中,每一行定义一个环境变量的键值对:

MY_ENV_VAR=value
ANOTHER_ENV_VAR=another_value

然后通过 --env-file 参数将该文件传递给 Docker 容器:

docker run --env-file .env my_image

3.3 在 Dockerfile 中使用 ENV 指令

在构建镜像时,可以在 Dockerfile 中使用 ENV 指令来设置环境变量:

FROM ubuntu:latest
ENV MY_ENV_VAR=value

这将创建一个在容器运行时可用的环境变量 MY_ENV_VAR

3.4 使用 docker-compose 中的环境变量

在使用 docker-compose 管理多个容器时,可以在 docker-compose.yml 文件中定义环境变量:

version: '3'
services:
webapp:
image: my_image
environment:
- MY_ENV_VAR=value
- ANOTHER_VAR=another_value

此外,也可以从 .env 文件加载环境变量:

version: '3'
services:
webapp:
image: my_image
env_file:
- .env

3.5 通过 docker exec 查看环境变量

可以通过 docker exec 进入容器内部,使用 envprintenv 命令查看容器中的环境变量:

docker exec -it container_id env

4. 环境变量的作用与实践

环境变量通常用于以下几种场景:

4.1 数据库连接信息

在多环境部署中,数据库连接信息可以通过环境变量配置,以避免在源代码中硬编码这些信息。例如:

docker run -e DB_HOST=localhost -e DB_USER=root -e DB_PASS=secret my_image

4.2 API 密钥

很多应用依赖于外部服务的 API 密钥,这些密钥可以通过环境变量来传递,以避免泄露。例如:

docker run -e API_KEY=your_api_key my_image

4.3 配置不同的运行环境

可以根据不同的环境传递不同的环境变量值,如开发、测试和生产环境。例如,在生产环境中你可能需要开启调试日志,但在开发环境中关闭它。

docker run -e ENV=production -e LOG_LEVEL=error my_image

5. 容器间共享环境变量

在多容器的场景中,如果需要多个容器共享环境变量,可以通过 Docker 网络和服务间的环境变量传递来实现。例如,使用 Docker Compose 启动多个服务时,web 服务可以访问 db 服务的环境变量。

6. 限制和注意事项

  • 敏感信息:环境变量可以在 Docker 容器启动时传递,但它们也有泄露的风险。例如,容器日志或操作系统的某些工具可能会暴露这些变量。
  • 变量覆盖:在容器运行时,环境变量的值可能会被外部传递的变量覆盖。例如,在 docker-compose.yml 中设置的环境变量可以在 docker run 时通过 -e 参数覆盖。
  • 共享变量的作用域:在 Docker Compose 或多容器应用中,环境变量的作用域仅限于指定的容器,跨容器传递时需要显式声明。

简介下这个 .net 开发的小系统

https://kf.shengxunwei.com/

升讯威在线客服与营销系统是一款客服软件,但更重要的是一款营销利器。

  • 可以追踪正在访问网站或使用 APP 的所有访客,收集他们的浏览情况,使客服能够主动出击,施展话术,促进成单。
  • 可嵌入网站、手机 APP、公众号、或者通过 URL 地址直接联系客服。
  • 支持访客信息互通,可传输访客标识、名称和其它任意信息到客服系统,与您的业务系统对接。
  • 可全天候 7 × 24 小时挂机运行,网络中断,拔掉网线,手机飞行模式,不掉线不丢消息,欢迎实测。

希望能够打造: 开放、开源、共享。努力打造 .net 社区的一款优秀开源产品。

钟意的话请给个赞支持一下吧,谢谢~

在线客服的独立产品之路:如何将复杂的 .NET 系统打包到 Docker 镜像,使之能一键上线的更多相关文章

  1. 使用 WPF+ ASP.NET MVC 开发 在线客服系统 (一)

    近段时间利用业余时间开发了一套在线客服系统,期间遇到过大大小小不少问题,好在都一一解决,最终效果也还可以,打算写一个系列的文章把开发过程详细的记录下来. 希望能够和更多的开发人员互相交流学习,也希望有 ...

  2. .net core 和 WPF 开发升讯威在线客服与营销系统:系统总体架构

    本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程.本产品已经成熟稳定并投入商用. 在线演示环境:https://kf.shengxunwei.com 注意 ...

  3. CentOS 30分钟部署 .net core 在线客服系统

    前段时间我发表了一系列文章,开始介绍基于 .net core 的在线客服系统开发过程.期间有一些朋友希望能够给出 Linux 环境的安装部署指导,本文基于 CentOS 8.3 来安装部署.在本文中我 ...

  4. Linux + .net core 开发升讯威在线客服系统:同时支持 SQL Server 和 MySQL 的实现方法

    前段时间我发表了一系列文章,开始介绍基于 .net core 的在线客服系统开发过程. 有很多朋友一直提出希望能够支持 MySQL 数据库,考虑到已经有朋友在用 SQL Server,我在升级的过程中 ...

  5. Linux 运行升讯威在线客服系统:同时支持 SQL Server 和 MySQL 的实现方法

    前段时间我发表了一系列文章,开始介绍基于 .net core 的在线客服系统开发过程. 有很多朋友一直提出希望能够支持 MySQL 数据库,考虑到已经有朋友在用 SQL Server,我在升级的过程中 ...

  6. Vue在线客服系统【开源项目】

    1. 项目介绍 一个基于Vue2.0的在线客服系统. 技术栈包含:Vue.VueX.Vue Router.Element UI. 2. 功能介绍 项目包含了2个模块:客服端和访客端. 2.1 客服端功 ...

  7. 百度AI开放平台 UNIT平台开发在线客服 借助百度的人工智能如何开发一个在线客服系统

    这段时间在研究一些人工智能的产品,对比了国内几家做人工智能在线客服的,有些接口是要收费的,有些是免费的,但是做了很多限制,比如每天调用的接口次数限制是100次.后来就找到了百度的AI,大家也知道,目前 ...

  8. .net core 和 WPF 开发升讯威在线客服与营销系统:背景和产品介绍

    本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程.本产品已经成熟稳定并投入商用. 在线演示环境:https://kf-m.shengxunwei.com ...

  9. .net core 和 WPF 开发升讯威在线客服与营销系统:(插曲)一次端口攻击行为的分析与应对

    本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程.本产品已经成熟稳定并投入商用. 在线演示环境:https://kf.shengxunwei.com 注意 ...

  10. .net core 和 WPF 开发升讯威在线客服与营销系统:使用 WebSocket 实现访客端通信

    本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程.本产品已经成熟稳定并投入商用. 在线演示环境:https://kf.shengxunwei.com 注意 ...

随机推荐

  1. nginx之日志

    1)耗时问题定位 这几天在优化服务器的响应时间,在根据 nginx 的 accesslog 中 requesttime进行程序优化时,发现有个接口,直接返回数据,平均的requesttime进行程序优 ...

  2. Vue.js 事件绑定

    1.事件监听 v-on:eventName可以简写成@eventName 事件对象:在HTML中,事件参数为$event,但是即使不传递,在回调函数中也可以直接使用event读取 <div id ...

  3. 【Amadeus原创】华为一键强制关闭后台应用的终极解决方法

    华为手机速度是快,用起来很顺手,但是最让人头疼的,就是紧急情况开会,我音乐关不了. 上划把全部应用删掉,也没用. 经过一阵子摸索,发现终极办法: 1, 打开华为自带的 手机助手- 应用启动管理 2, ...

  4. 在 .NET 下,Fiddler 不再抓取 Web Service 流量问题

    在 .NET 下,Fiddler 不再抓取 Web Service 流量问题 问题现象 原来的一个应用中,需要访问 SOAP 服务.在原来的 .NET Framework 版本中,使用 Fiddler ...

  5. 准备 OpenXML 开发环境

    Development with Open XML 1. 准备开发环境 1.1 Open XML SDK 现在最新的 OpenXML SDK 版本是 2.12.1 (2021/1),需要通过 NuGe ...

  6. Rocky Linux8升级9随记

    发现Rocky Linux已经升级了9.0版本,看着自己用着的8.5版本,跃跃欲试,于是就索性升级了.两者的支持年限没有太大的差别,先说我的想法:升不升级无所谓. 并不是9.0有什么特别牛的特性,只是 ...

  7. 用Python让两组数据纵向排序

    一.引言 在数据处理和分析中,排序是一项非常基础且重要的操作.排序可以帮助我们更好地理解数据,发现数据中的模式和规律.在Python中,我们可以使用多种方法对数据进行排序.本文将详细介绍如何使用Pyt ...

  8. 2024年1月Java项目开发指南3:创建Springboot项目

    本文档编写于贰零贰肆年一月八日@萌狼蓝天 如果你不知道什么是springboot,那么你只需要知道,这是一个让我们减少配置工作量,方便开发的开发框架,能让我们更专心于业务开发,省的被各种各样的配置浪费 ...

  9. 【MyBatis】学习笔记09:动态设置表名

    [Mybatis]学习笔记01:连接数据库,实现增删改 [Mybatis]学习笔记02:实现简单的查 [MyBatis]学习笔记03:配置文件进一步解读(非常重要) [MyBatis]学习笔记04:配 ...

  10. Netty SSL双向验证

    一· 快速命令 1.生成ca证书 openssl req -new -x509 -keyout ca.key -out ca.crt -days 36500在本目录得到 ca.key 和 ca.crt ...