Products
GG网络技术分享 2026-01-24 18:00 6
说实话,我真的不想写这玩意儿,dan是没办法啊,现在的环境就是这么卷。昨天晚上熬夜熬到头秃,就为了修那个该死的构建错误,真的是心态崩了。你说说咱们搞技术的图啥?不就是图个头发掉得慢一点吗? 太扎心了。 后来啊呢,Dockerfile 一摆在你面前,那就是妥妥的脱发加速器啊!dan是没办法,谁让它是云原生工程师的“吃饭家伙”呢?你要是不会写,出门dou不好意思跟人打招呼。
咱们今天就来聊聊这个让人又爱又恨的 Dockerfile。爱它是主要原因是它真的好用, 打包完扔哪douNeng跑;恨它是主要原因是写起来真的hen烦,特bie是当你面对那一堆报错的时候,真的想把电脑砸了卖废铁。

hen多人问我:“哎,大神,Dockerfile 到底是个啥?” 我通常dou会翻个白眼心想:大哥你百度一下会死吗?但我还是得赔笑脸解释。其实吧,你可yi把它想象成一张菜谱,huo者说是一份说明书。你想Zuo一盘红烧肉,你得告诉厨师先放油还是先放肉吧?Dockerfile 就是这个说明书。
我爱我家。 只不过这说明书是用代码写的, 而且厨师是个死脑筋的机器人,你少写个分号huo者拼错个单词,它就给你罢工,直接给你甩个大红脸Error出来一点面子dou不给。
这里面Zui基础的就是 FROM 指令了。这就好比你Zuo饭得先有锅有灶吧?FROM 告诉 Docker 你要从哪个基础镜像开始搞事,造起来。。
FROM ubuntu:20.04
kan这就完事了?kan着简单对吧?哼哼,天真!等你遇到了那个什么 Alpine Linux 你就知道什么叫痛了。那是真的小,确实小,只有几兆, 给力。 dan是缺库缺到你怀疑人生!你装个 Python 后来啊连 gcc dou没有,还得自己编译,编译失败那一刻,我真的栓Q了。
一言难尽。 接下来就是 RUN 指令了。这个指令是用来施行命令行的,比如装软件啊、改配置啊之类的。
RUN apt-get update && apt-get install -y vim
kan着没毛病吧?错!大错特错!我告诉你,初学者Zui喜欢干的事儿就是一行写一个 RUN:,何必呢?
RUN apt-get update
RUN apt-get install -y vim
这样写有啥问题呢?问题大了去了!Docker 是分层存储的,每一个 RUN dou是一层。你这么写,镜像瞬间变得巨大无比,就像吹气球一样,“呼”地一下就爆了。到时候部署的时候网速慢得像蜗牛爬, 老板拿着刀站在你身后问你为什么这么慢,你敢说是你乱写 RUN 造成的吗?你不敢!
suo以一定要合并命令, 一定要用 && 连起来还要记得把那些没用的缓存清理掉什么 apt-get clean 啊,rm -rf /var/lib/apt/lists/* 啊,这些dou是为了让镜像瘦下来不然你的磁盘空间分分钟被占满,报警邮件响个不停,烦dou烦死你了。
| 镜像名称 | 大概体积 | 适合干啥 | 吐槽指数 |
|---|---|---|---|
| Alpine | ~5MB | 追求极致小的变态 | ★★★★★ |
| Debian | ~70MB | 日常开发够用了 | ★★★ |
| Ubuntu | ~100MB+ | 啥dou有,随便造 | ★★ |
| CentOS | ~200MB+ | 老运维的Zui爱 | ★★★★ |
这两个指令真的是让人头秃的一对儿兄弟。COPY 就是复制,ADD 也是复制,那 ADD 多出来的功Neng是啥呢?它Neng解压!还Neng下载URL!听起来hen高级对不对,何不...?
dan是我跟你讲,千万别乱用 ADD 去下载 URL! 为啥?主要原因是那个缓存机制简直烂到爆! 你要是下载的文件变了怎么办?Docker 根本不知道!它会一直用旧的缓存给你构建, 准确地说... ran后你就在那儿纳闷儿:“卧槽?我怎么改了代码没生效?” 再说说排查半天发现是 ADD 的锅,这时候你的心态是真的想杀人。
suo以听哥一句劝, 老老实实用 COPY 复制本地文件,要是想下载东西用 RUN curl huo者 wget 配上管道解压,虽然麻烦点,dan是心里踏实啊!
COPY . /app
WORKDIR /app
这里又有个坑爹的地方 WORKDIR。千万别 cd 来 cd去的, 直接用 WORKDIR 设置工作目录, 不然你会迷失在一堆路径里, 找不到北. 别问我怎么知道的, dou是泪.,原来如此。
这两个简直是 Dockerfile 里Zui难理解 不如... 的相声演员. 一个是主程序启动命令, 一个是入口点.
我舒服了。 简单来说吧, ENTRYPOINT 就像是一个死心眼的守门员, CMD 就像是后面踢球的人. 你 docker run 后面加的参数, 会把 CMD 给覆盖掉, dan是覆盖不掉 ENTRYPOINT. suo以如guo你想让你的容器像一个可施行程序一样运行, 那就用 ENTRYPOINT.
如guo你只是想启动个 nginx huo者 java -jar 啥的, 用 CMD 就行了.
CMD
记得一定要用 JSON 数组的格式 , 别用 shell 格式 executable param1, 不然 PID 为 1 等着瞧。 的进程不是你的应用, 而是 shell, 你停容器的时候信号发不过去, 只Neng SIGKILL 强杀, 数据丢了别哭哦!
瞎扯。 以前咱们写 Dockerfile, 编译环境和运行环境dou在一个镜象里. 比如编译 Go 程序你得装 Go 编译器对吧? 编译完了其实运行的时候根本不需要 Go 编译器了啊! dan是它们还在镜象里占着茅坑不拉屎, 镜象几百兆甚至上G, 怎么kan怎么难受.
后来有了多阶段构建, 这玩意儿简直就是救命稻草.,我们一起...
# 第一阶段:编译
FROM golang:alpine AS builder
WORKDIR /go/src/app
COPY . .
RUN go build -o myapp
# 第二阶段:运行
FROM alpine:latest
COPY --from=builder /go/src/app/myapp /usr/local/bin/myapp
CMD
你kan懂了吗? 先在 builder 里把代码编译好, ran后在第二个阶段里只把编译好的二进制文件 COPY 过来. 这样到头来的镜象里只有二进制文件和一个可怜巴巴的 Alpine 系统, 小到飞起! 这种操作简直就是魔法, 第一次用的时候我dou惊呆了, 这特么才叫优雅!,也是没谁了...
你我共勉。 hen多人写了半天 Dockerfile 后来啊构建慢得像乌龟爬为啥? 主要原因是你把本地的 node_modules 啊, .git 啊, 还有那些乱七八糟的日志文件dou COPY 进去了!!!
.dockerignore 快给我加上!!!
嗐... ENV 是环境变量, 容器跑起来的时候也Neng用; ARG 是构建参数, 只有在你 docker build 的时候Neng用.
hen多新手喜欢把密码写在 ENV 里:
ENV PASSWORD=my_password_123
千万别这么Zuo!!!!!
恳请大家... Docker image 的层级信息里是Nengkan到这些变量的! 谁douNengkan见你的密码! 就像你在大街上裸奔一样! 密码这种敏感信息一定要tong过 docker run -e huo者 secrets 的方式传进去, huo者用 ARG 在构建时传入, 反正千万别硬编码在 Dockerfile 里!
你以为写完 Dockerfile 就完了? naive! 你还得把它推到仓库里去, ran后再写一堆 YAML 文件给 Kubernetes 用.,你看啊...
| 资源类型 | 干嘛用的 | 我的评价 |
|---|---|---|
| Pod | 一群容器的集合 | Zui小的调度单位, 动不动就挂, hen脆弱 |
| Deployment | 管理 Pod 副本数 | 升级回滚全靠它, 挺好用的就是配置太长了 |
| Service | 负载均衡和服务发现 | NodePort 在本地还行, Ingress 才是王道 |
| ConfigMap/Secret | 存配置和密码的 | 挂载成文件有时候会有权限坑, 注意一下 |
拭目以待。 有时候你本地跑得好好的 Docker 容器, 一扔进 K8s 就起不来. 为什么? 主要原因是网络不通啊! DNS 解析不了啊! huo者是健康检查没过啊!
胡诌。 特bie是那个健康检查! 记得在你的应用里专门写个 /health 接口返回 HTTP 200 要不然 K8s 怎么知道你还活着? 它以为你挂了就会把你重启杀掉 RestartPolicy=Always 可不是开玩笑的.
何不... 说了这么多废话其实就想表达一个意思:Dockerfile hen重要fei常重要特bie重要! 虽然它有时候hen烦人虽然它的报错信息有时候hen不友好虽然网络经常抽风... dan是掌握了它你就掌握了云原生的半壁江山.
让我们一起... 别再用手动部署服务器了那种原始人一样的方法早就该扔进垃圾桶了拥抱容器化拥抱自动化哪怕过程hen痛苦但后来啊是爽歪歪的kan着你的服务秒级扩容缩容是不是觉得自己像个魔法师?
行了行了我也累了打这么多字手dou酸了希望Neng帮到哪怕一个人吧要是觉得有用就点个赞没用就当kan个乐呵反正我是尽力了再见!
Demand feedback