Feb 8, 2023
初始流程
最早的部署流程是,多项目混合部署。将小流量业务统一部署,以更高效使用jdos资源。建立一个专用部署git工程假设为fe-deploy,使用submodule的形式,分别依赖其余所有工程。
当进行部署时,先在各个依赖工程内进行开发。Push至远端后,在fe-deploy中使用git submodule update把远端分支对于子模块的引用更新同步到本地。再在整体fe-deploy工程内,使用dockerfile进行容器化部署。
// fe-deploy 的 Dockerfile WORKDIR /tmp 设置容器内的工作目录为 /tmp。这意味着后续的命令都将在这个目录下执行。 COPY / ./web 将构建上下文(通常是 Dockerfile 所在的目录及其子目录)的所有内容复制到容器的 /tmp/web 目录中。 RUN cd web && cp -r * /www/wwwroot && rm -rf /tmp/* 切换到 /tmp/web 目录,将所有内容复制到 /www/wwwroot,然后删除 /tmp 下的所有文件。这个步骤是在准备最终的运行目录。 COPY nginx/*.conf /www/domains/ 将构建上下文中 nginx 目录下的所有 .conf 配置文件复制到容器的 /www/domains/ 目录中。 ENTRYPOINT /usr/sbin/sshd && nginx && sleep 99999999d 设置容器的入口点,启动 SSH 服务和 Nginx 服务,执行一个长时间的睡眠操作,保持容器不退出
Docker基本知识(逃)
Images: 镜像是一个只读的模板,包含运行容器所有内容:代码、运行时、库、环境变量和配置文件。用于创建 Docker 容器。
Containers: 镜像的运行实例。轻量级、可执行的软件包,运行应用及其所需的环境。
docker run -d -p 5000:5000 my-flask-app
Repositories:存储和分发镜像的地方,公共仓库Docker Hub。
Dockerfile: 自动构建一个给定的 Docker 镜像,定义构建镜像的步骤。
// 构建 docker build -t my-flask-app .
Docker-Compose:为了简化容器管理和网络设置,用于定义和运行由多个容器组成的 Docker 应用。
// 版本 version: '3' services: web: // 在当前目录下查找 Dockerfile 并构建镜像。 build: . // 将容器的 5000 端口映射到宿主机的 5000 端口 ports: - "5000:5000" // 设置一个环境变量,如指定 Redis 服务地址 environment: - REDIS_HOST=redis // 将当前目录(宿主机上的目录)挂载到容器内的 /app 目录 volumes: - .:/app // 依赖 depends_on: - redis redis: // 使用镜像 image: "redis:alpine" // 启动服务,通过 Docker Compose 配置的网络,容器间可以互相发现并通信。 docker-compose up --build
多阶段构建:
- 减小镜像大小:仅将生成的产物复制到最终镜像
- 优化构建缓存:Docker 分层架构,将不同的构建步骤分离到不同的阶段
- 提高安全性:构建阶段使用的工具和依赖不会包含在最终镜像中,从而减少了潜在的安全风险
Docker SSH安全问题
内部原则上不推荐用户以任何形式新增/修改 SSH 连接凭证,并通过非标流程访问线上实例(不论是否为弱口令),鼓励使用堡垒机进行登录。
但在jdos部署平台,ENTRYPOINT命令中必须带有/usr/sbin/sshd以供堡垒机和日志定时清理服务的可用性。如果必要使用 SSH 时,推荐使用非对称密钥形式认证并妥善保管私钥。
那非对称加密是如何工作的?
客户端上:
- 客户端生成一对密钥,一个私钥和一个公钥。
- 私钥保留在客户端。
容器终端上:
- 服务器向客户端发送一个随机生成的消息,用客户端的公钥加密的。
- 客户端使用其私钥解密,将结果发送回服务器。
- 客户端正确地解密了消息并发送回了正确的响应,服务器就知道客户端持有匹配的私钥,因此允许连接。
本质上是公钥加密,私钥解密,进行身份验证,这就涉及到了对Dockerfile的更改。
# 基础镜像 FROM some-base-image # 复制配置文件 COPY nginx/*.conf /www/domains/ # 创建.ssh目录并设置权限 RUN mkdir -p /root/.ssh && \ chmod 700 /root/.ssh # 复制公钥到authorized_keys。 # 当客户端尝试通过 SSH 连接到服务器时,服务器会使用存储在 authorized_keys 中的公钥来验证客户端。 # 如果在构建镜像时没有指定 SSH_PUB_KEY,会被设置为空字符串 RUN echo "$SSH_PUB_KEY" > /root/.ssh/authorized_keys # 设置authorized_keys的权限 RUN chmod 600 /root/.ssh/authorized_keys # 配置 ENTRYPOINT ENTRYPOINT /usr/sbin/sshd && nginx && sleep 99999999d
混合部署潜在问题
启动 Nginx 配置在堡垒机上,执行项目启动脚本时会包含对配置文件的引用,Nginx 将被启动并加载这些配置文件。
include /www/domains/*.conf;
虽然节约了容器资源,但这样的混部架构带来的问题主要有几点,
- 资源分配:单个容器中运行多个应用可能会导致资源竞争
- 故障隔离:多个应用共享同一个运行环境(即容器)可能会影响故障隔离。一个应用的问题可能会影响到容器中的其他应用。
- 安全性:如果一个应用被攻破,攻击者可能会更容易访问同一个容器中的其他应用。
- 开发效率:多个项目的同时部署,导致构建时间过长。
需迁移项目至单独的CICD流程,每个项目和流量分发配置相绑定,有单独自己的容器IP,通过主机名转发到真实IP。
//单独启动脚本示例 server { //监听 80 端口(HTTP 的默认端口) listen 80; //访问日志和错误日志的存储路径 access_log /export/a.com_access_80.log main; error_log /export/a.com_error_80.log; //server块处理来自 alpha.a.com 的请求 server_name a.com; //服务器从目标目录中提供静态文件 root /www/wwwroot/a.com/dist; // 设置客户端请求体的最大大小。这里设置为 0,意味着不限制请求体的大小 client_max_body_size 0; location / { //设置不同类型文件的缓存策略 if ($request_filename ~* .*\.(gif|jpg|jpeg|png|bmp|swf|flv|ico)$) { expires 30d; } if ($request_filename ~* .*\.(js|css)$) { expires 7d; } if ($request_filename ~* ^.+\.(eot|ttf|otf|woff|svg)$) { expires max; } if ($request_filename ~* ^.+\.html$) { expires -1; } //按顺序提供请求的文件。如果找不到,会转到 @router 标签的 location。 //$uri 是一个变量,表示当前请求的 URI。Nginx 首先尝试找到与 $uri 相匹配的文件。如果找不到,它再尝试将 $uri 当作一个目录来处理。 try_files $uri $uri/ @router; } location @router { //路由回退,找不到文件时,回退到 /index.html rewrite ^.*$ /index.html last; } location ^~ /api { //匹配所有以 /api 开头的请求,并重写 URL,然后将请求代理到 http://alpha-a.com rewrite /api/(.+)$ /$1 break; proxy_pass http://alpha-a.com; proxy_set_header Host alpha-a.com; } location ~* \.(ini|docx|txt|doc|map)$ { //禁止特定文件的访问 deny all; } location /logs/ { //禁止访问 /logs/ 目录下的所有内容。 autoindex off; deny all; } }
NGINX 关键词
- 事件驱动模型:异步、非阻塞处理网络事件。
- Master-Worker 架构
- Master 进程:Nginx 启动首先运行的是 master 进程。master 进程的主要职责是读取和验证配置文件、管理 worker 进程。
- Worker 进程:worker 进程负责处理客户端的请求,每个 worker 进程都是独立的,各自处理进入的请求。非阻塞,每个 worker 能够同时处理数千并发连接和请求。
- 负载均衡/反向代理
- 静态托管
深入了解:
- Docker 从入门到实践,https://yeasy.gitbook.io/docker_practice/contributing
- NGINX 文档,https://nginx.org/en/docs/
ENTRYPOINT /usr/sbin/sshd的设置许通过 SSH 进行远程登录,以兼容现有的工作流程。但同时会有潜在问题,安全性:如果 SSH 配置不当或使用了弱密码,运行 SSH 服务可能会引入额外的安全风险。设计理念:Docker 的理念是“一个容器,一个服务”。Docker 替代方案:
docker exec
命令启动一个容器内的 Shell 会话。