Day27-保护鲸鱼人人有责(二)

前言

昨天已经介绍了几个写 Dockerfile 时该注意的地方,但其实需要注意的地方非常非常多,所以今天会再补充两个,话不多说马上开始吧!

只 COPY 需要的东西

平常在写 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.jsonpackage-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 开始跑,因此可以大幅缩减需要等待的时间

用 multi-stage build 舍弃不需要的档案

这跟上一点有点类似,简单来说就是不要留任何不需要的东西在 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 更安全,那就连这些小细节都不能放过哦~


<<:  DAY30 - 完赛心得与下一步

>>:  自动化测试,让你上班拥有一杯咖啡的时间 | Day 28 - cypress 截图与影片

【第一天 - Leetcode 介绍】

Q1. 什麽是 Leetcode ? Leetcode 是一个线上练程序网站,收集了许多软件工程师面...

总结

这个系列开始我们先介绍了 RSS feed 里面的内容和不同平台的格式,也了解到要一次处理这麽多又有...

MySQL:如何让 query 区分大小写

前言 预设 MySQL 的表和 query 是不分大小写的。 (对,并不是所有资料库都这样) 举个例...

20.unity换场景

今天要盖出阿嬷家!让小红帽走进阿嬷家,找到阿嬷。 1.新建场景 右键 > Create >...