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,容器一启动文件找不着。
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 整体流程回顾
这一套流程其实就五步:
- 准备Dockerfile
- 编写测试脚本
- 构建镜像(docker build)
- 运行容器(docker run)
- 验证结果
你想象一下,以后你开发国密应用,只需把上面的脚本换成你的业务代码,把OpenSSL换成GmSSL或国密SDK,整个流程完全一样。这就是容器化的价值——一次构建,到处运行。
下面这张图把整个流程串起来了,你可以对照着看。
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,流程完全一样。记得保持镜像轻量,依赖明确,脚本可复现——这就是容器化的精髓。