docker(三、dockerfile)

  • 概述:dockerfile是一个用来构建镜像的文件。
  • 在实际工作中,构建镜像的基本步骤
  • 编写Dockerfile
  • 通过Dockerfile构建镜像
  • 通过镜像产生容器
  • dockerfile书写规则
  • (#)表示注释
  • 每个指令都是大写字母
  • 指令是按照从上到下的顺序执行的
  • docker执行dockerfile的流程
  • docker从基础镜像运行一个容器
  • 执行一条指令并对容器进行修改
  • 执行类似于docker commit的操作提交一个新的镜像层
  • docker在基于刚提交的下一条指令运行一个新的容器
  • 直到所有指令执行完成
  • docker hub中golang的Dockerfile
FROM buildpack-deps:stretch-scm

# gcc for cgo
// 配置golang所需的开发环境,这条命令需要较长的时间
RUN apt-get update && apt-get install -y --no-install-recommends \
		g++ \
		gcc \
		libc6-dev \
		make \
		pkg-config \
	&& rm -rf /var/lib/apt/lists/*

ENV GOLANG_VERSION 1.12.5

RUN set -eux; \
	\
# this "case" statement is generated via "update.sh"
	dpkgArch="$(dpkg --print-architecture)"; \
	case "${dpkgArch##*-}" in \
		amd64) goRelArch='linux-amd64'; goRelSha256='aea86e3c73495f205929cfebba0d63f1382c8ac59be081b6351681415f4063cf' ;; \
		armhf) goRelArch='linux-armv6l'; goRelSha256='311f5e76c7cec1ec752474a61d837e474b8e750b8e3eed267911ab57c0e5da9a' ;; \
		arm64) goRelArch='linux-arm64'; goRelSha256='ff09f34935cd189a4912f3f308ec83e4683c309304144eae9cf60ebc552e7cd8' ;; \
		i386) goRelArch='linux-386'; goRelSha256='146605e13bf337ff3aacd941a816c5d97a8fef8b5817e07fcec4540632085980' ;; \
		ppc64el) goRelArch='linux-ppc64le'; goRelSha256='e88b2a2098bc79ad33912d1d27bc3282a7f3231b6f4672f306465bf46ff784ca' ;; \
		s390x) goRelArch='linux-s390x'; goRelSha256='168d297ec910cb446d1aea878baeb85f1387209f9eb55dde68bddcd4c006dcbb' ;; \
		*) goRelArch='src'; goRelSha256='2aa5f088cbb332e73fc3def546800616b38d3bfe6b8713b8a6404060f22503e8'; \
			echo >&2; echo >&2 "warning: current architecture ($dpkgArch) does not have a corresponding Go binary release; will be building from source"; echo >&2 ;; \
	esac; \
	\
	url="https://golang.org/dl/go${GOLANG_VERSION}.${goRelArch}.tar.gz"; \
	wget -O go.tgz "$url"; \
	echo "${goRelSha256} *go.tgz" | sha256sum -c -; \
	tar -C /usr/local -xzf go.tgz; \
	rm go.tgz; \
	\
	if [ "$goRelArch" = 'src' ]; then \
		echo >&2; \
		echo >&2 'error: UNIMPLEMENTED'; \
		echo >&2 'TODO install golang-any from jessie-backports for GOROOT_BOOTSTRAP (and uninstall after build)'; \
		echo >&2; \
		exit 1; \
	fi; \
	\
	export PATH="/usr/local/go/bin:$PATH"; \
	go version

ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH

RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
WORKDIR $GOPATH

Dockerfile指令说明

  • Dockerfile指令一般被分为两种:配置指令与操作指令
  • 配置指令
ARG					定义创建过程中使用的变量
FROM				指定所创建镜像的基础镜像
LABEL				为生成的镜像添加元数据
EXPOSE				声明镜像内的服务监听的端口
ENV					指定环境变量
ENTRYPOINT			镜像的默认入口命令
VOLUME				创建一个数据卷
USER				指定运行容器时的用户名或UID
WORKDIR				配置工作目录
ONBUILD				创建子镜像的时候,自动执行的一些操作指令
SHELL				默认的shell类型
  • 操作指令
RUN					运行指定命令
CMD					启动容器时默认执行的命令
ADD					添加文件/数据到镜像中
COPY				复制文件/数据到镜像中

docker build通过dockerfile创建镜像的基本步骤

  • 查找dockerfile
  • 查找当前路径以及上当路径的子目录
  • 如果没有可以通过-f进行指定
  • 将该路径下所有数据作为上下文发送给docker服务端
  • 服务端校验Dockerfile
  • 逐条执行Dockerfile中的指令
  • 在执行指令的过程中,碰到ADD、COPY、RUN指令会生成一层新的镜像
  • 返回最终镜像的生成ID

常用命令:

Usage:	docker build [OPTIONS] PATH | URL | -

Build an image from a Dockerfile

Options:
      --add-host list           添加自定义的主机名到IP的映射
      --build-arg list          添加创建时的变量
      --compress                使用gzip来压缩创建上下文数据
  -f, --file string             指定Dockerfile名称
      --force-rm                删除中间过程的容器
      --iidfile string          将镜像ID写入文件
      --isolation string        容器的隔离机制
      --label list              Set metadata for an image
      --pull                    总是深度获取镜像的最新版本
  -q, --quiet                   不打印创建过程中的日志信息
      --rm                      创建成功后自动删除中间过程的容器
  -t, --tag list                指定镜像的标签

进一步了解:

  • docker 在运行时分为Docker引擎(服务端的守护进程),以及客户端工具,我们在日常使用docker各种命令实际上是在用docker客户端与引擎进行交互。
  • 所以在使用docker build来构建镜像时,构建镜像的过程是在docker引擎中完成的,而不是在本机环境完成的
  • docker build ..号指的是在镜像构建过程中的上下文环境的目录
  • 在创建dockerfile过程中,需要注意的问题:不要在Dockerfile路径下放无关数据,因为docker会将该路径下所有数据作为上下文发送给docker服务端,如果该路径太大,影响构建效率

构建镜像

  • 选择父镜像:父镜像是要生成的镜像的基础,会直接影响到生成的镜像的大小和功能

在Dockerfile中,通过FROM指定父镜像:

FROM scratch
# scratch表示空镜像
ADD hello /    # 把一个hello可执行文件添加到容器根目录下
CMD ["/hello"]  # 执行命令
  • 编写golang测试代码
// hello
package main

import "fmt"

func main(){
    fmt.Printf("hello")
}
  • 编译hello.go,生成hello可执行文件go build -o hello hello.go
  • 构建镜像:docker build -t hello-tencent .,命名为hello-tencent,标签默认为latest,指定当前目录为上下文路径(将当前目录的所有文件打包到docker服务器)
  • 运行docker:docker run -it hello-tencent,输出hello
  • 使用.dockerignore文件:
    docker build的过程中,指定的上下文目录中不是所有文件都会在Dockerfile文件中使用到,此时就可以指定在传递给docker 引擎时需要忽略掉的文件或文件夹

多步骤创建

  • 对于需要编译的应用的来说,一般至少要两个环境的docker的docker镜像
  • 编译环境镜像:包括完整的编译引擎、依赖库,往往会比较庞大,主要是编译应用为二进制文件
  • 运行环境镜像:复用编译好的二进制文件,运行应用,不需要编译环境,体积比较少
  • 可以通过多步骤创建,实现单一的Dockerfile,降低维护复杂度

之前是在centos中编译后,在docker中运行,现在将编译工作也转移到docker中:

  • 步骤:
  • 编写golang代码
// hello
package main

import "fmt"

func main(){
    fmt.Printf("hello")
}
  • 编写dockerfile
## 步骤一
FROM golang:1.8 as builder # 好几百M,可能会出现retrying

## 创建一个测试目录
RUN mkdir -p /go/src/test

## 配置工作目录
WORKDIR /go/src/test

## 将main.go拷贝到工作目录下
COPY main.go .

## 系统配置,生成应用程序
RUN CGO_ENABLE=0 GOOS=linux go build -o app .


## 步骤二
FROM alpine:latest

WORKDIR /root/

# 将前面获取到的go环境拷贝过来,才能运行app应用程序
COPY --from=builder /go/src/test/app .

CMD["./app"]

构建镜像:docker build -t test-mul-go:latest .

运行docker:docker run -it test-mul-go,输出hello

tomcat实战