昨天已经介绍了几个写 Dockerfile 时该注意的地方,但其实需要注意的地方非常非常多,所以今天会再补充两个,话不多说马上开始吧!
平常在写 Dockerfile 时,有些人为了一时方便,会直接用 COPY . /app
把整个专案资料夹复制到 container 的 /app
资料夹内。这样不用动太多脑筋,在 container 里面也可以直接存取到所有档案,但这样的做法可以说是糟透了
FROM node:14
WORKDIR /app
# Very BAD
COPY . .
RUN npm install
RUN npm run test
CMD ["node", "index.js"]
首先是这样会让 image 变得很肥(连 node_modules
都进去了能不肥吗XD),而且一不小心就会把 .envrc
这类敏感资料一起放进去,如果哪天这个 image 被骇客拿到,里面的 AWS 凭证、资料库密码等等超机密资料就会直接外泄出去,哪天突然被删库也是有可能的
为了避免这种事情发生,在 build image 时应该只把需要的东西复制进去,譬如说你马上就要跑 npm install
,这才把 package.json
跟 package-lock.json
放进去,而程序码也是把真的会跑到的那些放进去就好
FROM node:14
WORKDIR /app
# Good
COPY package.json package-lock.json ./
RUN npm install
# Good
COPY src/ index.js ./
RUN npm run test
CMD ["node", "index.js"]
而且这样还有另外一个好处,就是如果你改了 src
里面的程序码,但没有安装新的 package(开发时大部分都是这样吧~),因为 Docker 会自动做 cache,所以就不需要重新跑一次 npm install,会直接从第 10 行的 npm run test
开始跑,因此可以大幅缩减需要等待的时间
这跟上一点有点类似,简单来说就是不要留任何不需要的东西在 image 里面(没用的东西都给我滚),即便那是 build image 过程中产生的东西也是一样
譬如说原本 Go API server 的 Dockerfile 可能长这样,因为要在 build image 时编译出执行档,所以第 5 行的 COPY *.go
是一定要的,没有他们就无法进行编译
FROM golang:1.17
WORKDIR /app
COPY *.go go.mod go.sum ./
RUN go build -o main
CMD ["./main"]
但说真的一旦编译出执行档之後,那些 Go 程序码就用不到了,所以应该来个爽快的过河拆桥,用 multi-stage build 把编译完的执行档保留下来就好,程序码什麽的就直接拜拜
像下面这个这个 Dockerfile 经过 multi-stage build 後 image 里面就只有 /app/main
这个编译好的执行档,没有任何程序码以及 Go 的编译器,非常的存粹
# compile stage
FROM golang:1.17 as compile-env
WORKDIR /app
COPY *.go go.mod go.sum ./
RUN go build -o main
# final stage
FROM gcr.io/distroless/base
COPY --from=compile-env /app/main /app
CMD ["/app/main"]
那这样有什麽好处呢?除了 image 可以变小很多之外,即便 image 被骇客拿到了,程序码也不会外流出去(有很多攻击都是拿到程序码後从里面找到漏洞),因此只保留执行档可以提高安全性
除此之外,因为环境越复杂就越可能有没发现的漏洞,而把 base image 从原本的 golang:1.17
换成 Google 提供的 distroless image 刚好可以大幅减少环境的复杂度(distroless 几乎没装什麽东西,连 shell 都没有),也就可以提高安全性
这两天介绍了一些在写 Dockerfile 时的注意事项,虽然很多都是小地方,但毕竟魔鬼藏在细节里,想要让你的 Docker image 更安全,那就连这些小细节都不能放过哦~
>>: 自动化测试,让你上班拥有一杯咖啡的时间 | Day 28 - cypress 截图与影片
=x= 🌵 建立 Specification Manager - Content Page 後台页面...
Q1. 什麽是 Leetcode ? Leetcode 是一个线上练程序网站,收集了许多软件工程师面...
这个系列开始我们先介绍了 RSS feed 里面的内容和不同平台的格式,也了解到要一次处理这麽多又有...
前言 预设 MySQL 的表和 query 是不分大小写的。 (对,并不是所有资料库都这样) 举个例...
今天要盖出阿嬷家!让小红帽走进阿嬷家,找到阿嬷。 1.新建场景 右键 > Create >...