博客:docker制作自己的镜像并上传dockerhub
dockerfile 内容
FROM golang:alpine AS builder
LABEL stage=gobuilder
ENV CGO_ENABLED 0
ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct
WORKDIR /build/zero
ADD go.mod .
ADD go.sum .
RUN go mod download
COPY . .
COPY service/hello/etc /app/etc
RUN go build -ldflags="-s -w" -o /app/hello service/hello/hello.go
FROM alpine
RUN apk update
ENV TZ Asia/Shanghai
WORKDIR /app
COPY
COPY
CMD ["./hello", "-f", "etc/hello-api.yaml"]
dockerfile 详解
#当我在/Users/myself/Golang/common_project/src/greet目录下执行 docker build -t hello:v1 -f service/hello/Dockerfile . 命令
# -f service/hello/Dockerfile 代表的事dockerfile文件的所在目录,可以是任意目录
# . 代表的是当前目录的所有文件,就是执行命令所在的目录下的文件,所以 greet目录下 的所有文件都会打包到 Docker引擎(服务端守护进程)
# 如果没有 . ,那么默认上下文路径就是 Dockerfile 所在的位置。
#所以首先会把 greet目录 打包到 守护进程,后面继续执行以下代码
#FROM <image>
#FROM <image>:<tag>
#FROM <image>@<digest>
#tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
#打包依赖阶段使用golang:alpine作为基础镜像
FROM golang:alpine AS builder
#维护者信息
MAINTAINER Dong Lei
MAINTAINER 2781897595@qq.com
MAINTAINER Dong Lei <2781897595@qq.com>
#LABEL:用于为镜像添加元数据
LABEL stage=gobuilder
#ENV:设置环境变量
ENV CGO_ENABLED 0
ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct
#WORKDIR:工作目录,类似于cd命令,进入/build/zero这个目录
WORKDIR /build/zero
#格式:
# WORKDIR /path/to/workdir
#示例:
# WORKDIR /a (这时工作目录为/a)
# WORKDIR b (这时工作目录为/a/b)
# WORKDIR c (这时工作目录为/a/b/c)
#注:
# 通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用
#ADD:将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget
# 因为复制的上下问目录是 greet,所以 将项目目录下的
# 把docekr守护进程下的 go.mod 拷贝到 /build/zero目录下
ADD go.mod .
ADD go.sum .
RUN go mod download
#COPY:功能类似ADD,但是是不会自动解压文件,也不能访问网络资源
# .是上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。
#解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。
#如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。
#注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢
#COPY <源路径>... <目标路径>
#COPY <src>... <dest>
#dest: 指得是镜像(image)中的路径
#src: 指得是Dockerfile所在的context路径
#那么COPY的作用就是:将构建镜像的电脑上的文件或者文件夹拷贝到镜像中去。
#我们知道,Dockerfile文件往往是放在github上的某个工程里,当我们checkout工程,然后执行 docker build 命令的时候,我们的电脑和作者的电脑肯定不一样的,所以,明白了这一点,基于这样最基本的常识,我们马上就能明白什么样的src是正确的,什么样的src是错误的:
#正确:
#COPY ./package.json /app/
#COPY package.json /usr/src/app/
#错误:
#COPY ../package.json /app 因为上一层目录大家都不一样的
#或者 COPY /opt/xxxx /app 有可能连操作系统都不一样,哪里有什么/opt这样的目录
#所以,Dockerfile中的COPY中的context(上下文)指得就是 Dockerfile 所在的工程中的目录结构,离开了这个工程的其他目录都是错误的。
#顺便说一下:dest 是可以在镜像中的任意位置的,这个无所谓,不用解释大家都明白了吧。
#COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。
#对于 COPY 和 ADD 命令来说,如果要把本地的文件拷贝到镜像中,那么本地的文件必须是在上下文目录中的文件。其实这一点很好解释,因为在执行 build 命令时,docker 客户端会把上下文中的所有文件发送给 docker daemon。考虑 docker 客户端和 docker daemon 不在同一台机器上的情况,build 命令只能从上下文中获取文件。如果我们在 Dockerfile 的 COPY 和 ADD 命令中引用了上下文中没有的文件,就会收到类似下面的错误:
#. 便是当前目录
# 如果在 Dockerfile 中这么写:
# COPY ./package.json /app/
# 这并不是要复制执行 docker build 命令所在的目录下的 package.json,也不是复制 Dockerfile 所在目录下的 package.json,而是复制 上下文(context) 目录下的 package.json。
# 因此,COPY 这类指令中的源文件的路径都是相对路径。这也是初学者经常会问的为什么 COPY ../package.json /app 或者 COPY /opt/xxxx /app 无法工作的原因,因为这些路径已经超出了上下文的范围,Docker 引擎无法获得这些位置的文件。如果真的需要那些文件,应该将它们复制到上下文目录中去。
#理解构建上下文对于镜像构建是很重要的,避免犯一些不应该的错误。比如有些初学者在发现 COPY /opt/xxxx /app 不工作后,于是干脆将 Dockerfile 放到了硬盘根目录去构建,结果发现 docker build执行后,在发送一个几十 GB 的东西,极为缓慢而且很容易构建失败。那是因为这种做法是在让 docker build 打包整个硬盘,这显然是使用错误。
# 把docekr守护进程下的所有文件 复制到 /build/zero 目录下,相当于 zero 就是 greet一样
COPY . .
#把service/hello/etc 这个文件夹 复制到 容器中 /app/etc
# 因为我是在greet 这个项目下执行的 打包命令 docker build -t hello:v1 -f service/hello/Dockerfile .
# 所以上下文就是 greet,相当于把 greet整个 拷贝到守护进程,所以
COPY service/hello/etc /app/etc
# 指定编译完成后的文件名,可以不设置使用默认的,最后一步要执行该文件名,因为service/hello/hello.go里面是mian函数编译到 /app/hello
RUN go build -ldflags="-s -w" -o /app/hello service/hello/hello.go
#通过上面的copy和RUN go 使 /app/etc 和 /app/hello 两个数据生成 ,/app/hello是编译后的文件,而不是文件夹
# 运行阶段指定scratch作为基础镜像
FROM alpine
#RUN用于在镜像容器中执行命令,其有以下两种命令执行方式:
#RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache
RUN apk update --no-cache && apk add --no-cache ca-certificates tzdata
ENV TZ Asia/Shanghai
# 进去app 目录
WORKDIR /app
#COPY --from=builder将上一层镜像复制制定目录复制到当前工作目录 上一阶 通过COPY 和 RUN go 生成的 /app/hello 复制到 /app/hello
COPY --from=builder /app/hello /app/hello
COPY --from=builder /app/etc /app/etc
# 执行结果如下
#/
#app bin dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var
#/
#/app
#etc hello
#/app
#CMD:构建容器后调用,也就是在容器启动时才进行调用。
#CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
CMD ["./hello", "-f", "etc/hello-api.yaml"]
案例1
dockerfile 文件
FROM golang:alpine AS builder
LABEL stage=gobuilder
ENV CGO_ENABLED 0
ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct
WORKDIR /build/zero
ADD go.mod .
启动容器
luwei@luweideMacBook-Pro-2 greet % docker build -t hello:v4 -f service/hello/Dockerfile .
[+] Building 81.4s (9/9) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 6.13kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/golang:alpine 80.4s
=> [auth] library/golang:pull token for registry-1.docker.io 0.0s
=> [internal] load build context 0.1s
=> => transferring context: 27B 0.0s
=> [1/3] FROM docker.io/library/golang:alpine@sha256:55da409cc0fe11df63a7d6962fbefd1321fedc305d9969da636876893e289e2d 0.0s
=> CACHED [2/3] WORKDIR /build/zero 0.0s
=> CACHED [3/3] ADD go.mod . 0.0s
=> exporting to image 0.1s
=> => exporting layers 0.0s
=> => writing image sha256:b1298754a175d735d9e8d767e025c0b4ccf8ee1f65b78bd6af8a091b4f36a1b5 0.0s
=> => naming to docker.io/library/hello:v4 0.0s
luwei@luweideMacBook-Pro-2 greet %
查看
luwei@luweideMacBook-Pro-2 greet % docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello v4 b1298754a175 42 hours ago 315MB
启动容器
可以看到 go.mod被复制到容器 /build/zero 中
luwei@luweideMacBook-Pro-2 greet % docker run -t -i hello:v4
/build/zero
go.mod
/build/zero
/bin/sh: cd: can't cd to go.mod: Not a directory
文件目录
为什么需要 ADD go.sum . 因为其实 go.sun 是在根目录下并不是 g.mod 目录下
案例2
dockerfile 文件
FROM golang:alpine AS builder
LABEL stage=gobuilder
ENV CGO_ENABLED 0
ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct
WORKDIR /build/zero
COPY . .
打包镜像
docker build -t hello:v4 -f service/hello/Dockerfile .
luwei@luweideMacBook-Pro-2 greet % docker build -t hello:v4 -f service/hello/Dockerfile .
[+] Building 88.6s (9/9) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 6.13kB 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/golang:alpine 83.7s
=> [auth] library/golang:pull token for registry-1.docker.io 0.0s
=> [1/3] FROM docker.io/library/golang:alpine@sha256:55da409cc0fe11df63a7d6962fbefd1321fedc305d9969da636876893e289e2d 0.0s
=> [internal] load build context 2.9s
=> => transferring context: 145.68MB 2.8s
=> CACHED [2/3] WORKDIR /build/zero 0.0s
=> [3/3] COPY . . 0.5s
=> exporting to image 1.0s
=> => exporting layers 1.0s
=> => writing image sha256:2a71b6880ec710842cd090ffbf44ece12ab49829981aec3a424739c1f208f224 0.0s
=> => naming to docker.io/library/hello:v4 0.0s
luwei@luweideMacBook-Pro-2 greet %
查看内容
内容和greet 内容一样的
/build/zero # ls
Dockerfile README.en.md README.md default.etcd go.mod go.sum service
案例3
dockerfile 文件
FROM golang:alpine AS builder
LABEL stage=gobuilder
ENV CGO_ENABLED 0
ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct
WORKDIR /build/zero
COPY . .
COPY service/hello/etc /app/etc
RUN go build -ldflags="-s -w" -o /app/hello service/hello/hello.go
FROM alpine
RUN apk update --no-cache && apk add --no-cache ca-certificates tzdata
ENV TZ Asia/Shanghai
WORKDIR /app
COPY --from=builder /app/hello /app/hello
COPY --from=builder /app/etc /app/etc
CMD ["./hello", "-f", "etc/hello-api.yaml"]
启动容器并进去
luwei@luweideMacBook-Pro-2 greet % docker run -t -i hello:v5 /bin/sh
/app
/app
etc hello
/app
请求测试
luwei@luweideMacBook-Pro-2 ~ % curl -i http://localhost:8889/from/you
HTTP/1.1 200 OK
Content-Type: application/json
X-Trace-Id: efd07feabdbedf9e3dd51e2eb6ddcb1b
Date: Thu, 25 Nov 2021 04:13:09 GMT
Content-Length: 14
{"message":""}%
luwei@luweideMacBook-Pro-2 ~ %