4、使用Docker创建第一个国密算法容器

好,咱们开始动手。上一章把Docker环境搭好了,现在该真正建一个能跑国密算法的容器。说白了,就是写个Dockerfile,然后build、run,整套流程走一遍。

我最早接触这个场景,是在帮客户迁移一个SM2签名服务。当时客户环境一团乱,依赖库版本不对,Python包冲突。后来我用Docker一包,所有问题全解决了。你想想看,同样的代码,换个环境就崩,这事儿多常见。

4.1 准备工作:确定你要跑的国密算法

在这之前,得先明确一件事——你打算在容器里跑哪个国密算法?SM2、SM3、SM4还是SM9?不同算法依赖的库不一样。我建议第一个容器用SM3试试,因为它不涉及密钥对生成和签名,纯哈希运算,容易验证。

算法 典型应用 依赖库示例 容器化难度
SM3 哈希、数字摘要 openssl(1.1.1+)、gmssl 低
SM4 对称加密 openssl、libressl 低
SM2 非对称加密、签名 gmssl、pysmx(Python) 中
SM9 标识密码 pbc、libsm9 高

我个人习惯先跑个SM3验证整个流水线通不通。等流程跑通了,再换其他算法。

4.2 编写Dockerfile——容器的“食谱”

Dockerfile就是你的构建脚本。嗯,这里要注意:写Dockerfile不是简单的把依赖装进去,而是要保证镜像体积小、构建快、安全。

下面是一个干净的Dockerfile,基于alpine镜像构建SM3测试环境:

FROM alpine:3.18

# 安装依赖
RUN apk add --no-cache openssl-dev openssl

# 创建一个测试目录
WORKDIR /app

# 复制一个简单的SM3测试脚本
COPY sm3_test.sh .

# 设置可执行权限
RUN chmod +x sm3_test.sh

# 默认运行脚本
CMD ["./sm3_test.sh"]

这里有两个小细节:

  • --no-cache 参数能减少镜像层中的缓存文件,我见过不少人忘了加,结果镜像大了几十MB。
  • WORKDIR 最好用路径,避免路径杂糅。我之前踩过坑,忘了设WORKDIR,容器一启动文件找不着。
我的经验: 如果你用的是 RHEL/CentOS 基础镜像,记得把 apk 换成 yum,库名也不一样。不过我个人更倾向 Alpine,镜像小、启动快,生产环境也常用。

4.3 构建镜像——docker build

有了Dockerfile,下一步就是构建。命令很简单:

docker build -t gm-sm3-demo:1.0 .

解释一下:-t 给镜像打标签,gm-sm3-demo:1.0 是镜像名和版本,最后的点表示Dockerfile在当前目录。

为什么会构建失败?最常见三个原因:

  • 网络问题拉不到基础镜像。我一般先 docker pull alpine:3.18 手动拉一下,确认能通。
  • Dockerfile里写错了路径或文件名。注意大小写,Linux系统路径区分大小写。
  • 缺少执行权限。像上面的 chmod 命令别忘了。
避坑指南: 我曾经有一次把 WORKDIR 写成了 WORKDIR /app/,多了一个斜杠,结果容器启动时目录没创建成功。后来排查了半天才发现。记住,WORKDIR 后面不要加斜杠。

构建完成后,用 docker images 查看一下镜像列表:

$ docker images
REPOSITORY       TAG       IMAGE ID       CREATED          SIZE
gm-sm3-demo      1.0       9a8b7c6d5e4f   10 seconds ago   25.6MB
alpine           3.18      616c5e6aefc3   2 months ago     7.05MB

你看,Alpine基础镜像才7MB,加上OpenSSL和我们的脚本,最终镜像也只有25.6MB,非常轻量。

4.4 编写SM3测试脚本

为了验证容器里的国密算法能正常工作,咱们写个简单的shell脚本,用OpenSSL计算SM3值:

#!/bin/sh
# sm3_test.sh

echo "Hello, 国密!" > /tmp/test.txt

# 使用OpenSSL计算sm3哈希(openSSL 1.1.1+ 支持SM3)
result=$(openssl dgst -sm3 /tmp/test.txt)
echo "$result"

注意:OpenSSL 1.1.1 及以上版本才支持SM3算法。如果你用的基础镜像只有1.1.0,那得换用GmSSL或者自己编译。我有个项目就碰到过,后来老老实实换了GmSSL的镜像。

4.5 运行容器——docker run

镜像建好了,脚本也写好了,现在运行:

docker run --rm gm-sm3-demo:1.0

--rm 表示容器运行完自动删除,省得留下一堆停止的容器。我每次测试都用这个参数,干净利落。

输出结果应该是类似这样的:

SM3(/tmp/test.txt)= 66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0

这说明SM3哈希计算成功了。你拿这个值跟标准工具对比一下,就能确认容器里的国密算法是否正常工作。

验证方法: 在宿主机上运行同样的命令 echo "Hello, 国密!" | openssl dgst -sm3,如果结果一致,就说明容器内的国密环境没问题。

4.6 整体流程回顾

这一套流程其实就五步:

  1. 准备Dockerfile
  2. 编写测试脚本
  3. 构建镜像(docker build)
  4. 运行容器(docker run)
  5. 验证结果

你想象一下,以后你开发国密应用,只需把上面的脚本换成你的业务代码,把OpenSSL换成GmSSL或国密SDK,整个流程完全一样。这就是容器化的价值——一次构建,到处运行。

下面这张图把整个流程串起来了,你可以对照着看。

构建并运行国密容器的核心流程 1. 编写Dockerfile 2. docker build 3. docker run 4. 容器内执行SM3 5. 验证哈希结果 输出哈希值 核心理念:Dockerfile → 镜像 → 容器 → 验证,形成一个闭环 镜像不可变,容器可丢弃,每次运行都能复现相同结果

4.7 记住几个常用命令

把这张表存起来,以后会频繁用到:

命令 作用 常用参数
docker build -t 名称:版本 . 构建镜像 -t 指定标签,-f 指定Dockerfile路径
docker run --rm 镜像名 运行容器并自动删除 -d 后台运行,-it 交互模式
docker images 列出本地镜像 --no-trunc 显示完整ID
docker ps -a 查看所有容器(包括已停止) -q 只显示ID
一个小习惯: 我每次构建完新镜像,都会第一时间运行一次 docker run --rm 看看能不能正常启动。如果启动报错,马上回头检查Dockerfile,不要等到后面集成再排查。

4.8 常见问题排查

第一次跑可能会遇到些小问题,我列几个常见的:

  • “exec: './sm3_test.sh': permission denied”——脚本忘记加执行权限了。在Dockerfile里加 RUN chmod +x 即可。我在生产环境里也犯过这个错,后来养成了习惯,复制完脚本立即加权限。
  • “no such command: sm3”——OpenSSL版本太老,不支持SM3。换用GmSSL或者升级到1.1.1+。我建议直接装GmSSL,国密支持更全。
  • 构建超级慢——可能是网络问题,可以换国内镜像源,或者在Dockerfile里用 --mirror 参数。

拿我自己的经历来说,有一次跑SM2签名容器,构建时没注意libssl版本,结果运行时提示找不到符号。后来我把基础镜像从Debian换成了Alpine,重新编译了一次,问题就解决了。所以你看,基础镜像的选择很关键。

好了,你的第一个国密容器已经跑通了。从这以后,你可以把任何国密算法都装进容器里,不管是SM2、SM3还是SM4,流程完全一样。记得保持镜像轻量,依赖明确,脚本可复现——这就是容器化的精髓。