Docker 是世界领先的软件容器平台,所以想要搞懂 Docker 的概念我们必须先从容器开始说起。
容器是一种轻量级的、可执行的独立软件包,包含软件运行所需的所有内容:代码、运行时环境、系统工具、系统库和设置。
容器虚拟化的是操作系统而不是硬件,是内核级的虚拟化,容器之间是共享同一套操作系统资源的。虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统。因此容器的隔离级别会稍低一些。
Docker 的镜像提供了除内核外的完整运行时环境,确保了应用运行环境一致性,避免再出现 “代码在这台机器上正常运行, 换台机器却不能启动; 应用在测试环境没问题, 在生产环境报错” 这类问题 ——一致的运行环境
可以做到秒级、甚至毫秒级的启动时间, 大大的节约了开发、测试、部署的时间。——更快速的启动时间
避免公用的服务器,避免资源容易受到其他用户的影响。——隔离性
善于处理集中爆发的服务器使用压力, 十分适合微服务;——弹性伸缩,快速扩展
docker兼容很多平台, 可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。——迁移方便
使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。——持续交付和部署
需要先安装docker,然后接下来介绍docker的组件和常用命令,以及如何使用dockerfile构建自定义的镜像
Docker 客户端-Client
Docker 服务端-Docker daemon
Docker 镜像-Image
Docker 容器-Container
Register -仓库
Docker采用的是CS架构,客户端使用docker command 命令行 与服务器进程 Docker daemon 通信。
Docker 内部组件 :镜像、容器、仓库
镜像(image):
Docker 镜像可以看作是创建容器的模板。
镜像的工作原理–分层存储
因为镜像包含操作系统完整的 根文件系统root fs,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 联合文件系统 Union FS的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。
镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。
分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。
容器(Container):
镜像和容器的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行的实体。容器可以被创建、启动、停止、删除等。
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。前面讲过镜像使用的是分层存储,容器也是如此。
容器存储层的生存周期和容器一样,容器被删除时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。如:容器内生成的各种日志文件, 当容器被删除时也会被删除. 正如一个对象被回收了,那他的所有成员变量占用的空间也就被释放了.
按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据 ,容器存储层要保持无状态化。**所有的文件写入操作,都应该使用数据卷(Volume) **,在这些位置的读写会跳过容器存储层,直接对宿主机(或网络存储)发生读写,其性能和稳定性更高。数据卷的生存周期独立于容器,容器被删除,数据卷也不会消失
仓库(Registry):
仓库是存放镜像的仓库,分为公有和私有两种;
最常使用的 Registry 公开服务是Docker官方的中心仓库 Docker Hub,这也是默认的 Registry,并拥有大量的官方维护的镜像;一般企业用户或者个人用户都会选择搭建属于自己的私有仓库,比如Harbor、Nexus。
Docker生态 – 三剑客
三剑客: docker, docker-compose, docker swarm
docker: 开源项目(go), 开源版本免费, 另有商业版本(有制裁风险)
docker-compose: Docker官方开源项目(Pyhon3), 用于编排一组容器, 使用docker-compose.yml配置文件, 可以同时启动一个项目需要使用的各种容器, 如mysql, redis, nginx, jar应用. 可以像脚本一样在新服务器上快速简单地部署项目
docker swarm: Docker公司官方推出的管理docker集群的平台,现在大部分市场份额都被google的k8s占去
服务端命令
安装docker: yum install docker
启动docker 服务端: service docker start
停止docker 服务端: service docker stop
查看docker 服务端的状态: service docker status
小试牛刀–hello-world
启动docker服务端之后, 执行 docker run hello-world
, 可以看到欢迎词, 显示如下
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
客户端命令
使用docker command -h 查看docker 客户端所有的命令用法
1.在仓库中搜索镜像: docker search
Usage: docker search [OPTIONS] TERM
Search the Docker Hub for images
Options:
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print search using a Go template
--limit int Max number of search results (default 25)
--no-trunc Don't truncate output
docker search nginx
搜索仓库中 nginx相关的镜像
2.从仓库中下载镜像: docker pull
Usage: docker pull [OPTIONS] NAME[:TAG|@DIGEST]
Pull an image or a repository from a registry
Options:
-a, --all-tags Download all tagged images in the repository
--disable-content-trust Skip image verification (default true)
使用 docker pull[IMAGE_NAME]:[TAG]
命令来下载镜像,其中 IMAGE_NAME
表示的是镜像的名称,而 TAG
是镜像的标签,也就是说我们需要通过 “镜像 + 标签” 的方式来下载镜像。
注意:
1.Docker 会尝试先从默认的镜像仓库(默认使用 Docker Hub 公共仓库)去下载,用户也可以自定义配置镜像仓库。
2.您也可以不显式地指定 TAG, 标签默认为 latest ,也就是最新版本。它是不稳定的, 在生产环境中,应显示指定具体的 TAG。
3.如果下载慢可使用国内镜像加速
docker pull centos:7
3.显示本机已下载的所有镜像: docker images
Usage: docker images [OPTIONS] [REPOSITORY[:TAG]]
List images
Options:
-a, --all Show all images (default hides intermediate images)
--digests Show digests
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print images using a Go template
--no-trunc Don't truncate output
-q, --quiet Only show numeric IDs
#使用 docker images命令
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql 5.7.27 383867b75fd2 10 months ago 373MB
redis 3.0.7-alpine 856249f48b0c 3 years ago 12.6MB
nginx alpine a624d888d69f 7 months ago 21.5MB
列表包含了 仓库名
、标签
、镜像 ID
、创建时间
以及 所占用的空间
。
其中仓库名、标签在之前的基础概念章节已经介绍过了。镜像 ID 则是镜像的唯一标识,一个镜像可以对应多个 标签。
注意:图中的镜像大小信息只是逻辑上的大小信息,因为一个镜像是由多个镜像层(
layer
)组成的,而相同的镜像层本地只会存储一份,所以 Docker 在下载之前,会去检测本地是否会有同样 ID 的层,如果本地已经存在了,就直接使用本地的就好了。真实情况下,占用的物理存储空间大小,可能会小于逻辑大小。
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
可以使用docker tag
命令,为本地镜像添加一个新的标签,相当于创建一个软连接/快捷方式,镜像 ID 是一样的,只是别名不同而已。
4.删除已下载的镜像: docker rmi
Usage: docker rmi [OPTIONS] IMAGE [IMAGE...]
Remove one or more images
Options:
-f, --force Force removal of the image
--no-prune Do not delete untagged parents
可以通过镜像名(repository:tag)或者镜像ID删除,
镜像名删除:如果镜像存在多个标签,那么删除就是删除一个标签而已;
镜像ID删除:它会先尝试删除所有指向该镜像的标签,然后在删除镜像本身。
当通过该镜像创建的容器未被全部销毁时,镜像无法直接被删除的。通过添加 -f
参数,可以强制删除镜像
5.启动容器: docker run
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Run a command in a new container
Options: 这里列了一些常用的参数
-d, --detach Run container in background and print container ID 后台运行容器,并返回容器ID(唯一)
-e, --env list Set environment variables 注入环境变量
-i, --interactive Keep STDIN open even if not attached 前台交互式运行
-l, --label list Set meta data on a container 对容器设置标签
--name string Assign a name to the container 设置容器名(唯一)
--network string Connect a container to a network (default "default")
--read-only Mount the container's root filesystem as read only
--rm Automatically remove the container when it exits
-p, --publish list Publish a container's port(s) to the host 宿主机端口与容器端口的映射
-t, --tty Allocate a pseudo-TTY 伪终端,一般和-i搭配
-v, --volume list Bind mount a volume 数据卷绑定(挂载),容器的数据可持久化
--volumes-from list Mount volumes from the specified container(s)
-w, --workdir string Working directory inside the container
#利用 docker run 来创建容器, 将容器内的80端口映射到宿主机的18000端口
docker run -d --name=nginx -p 18000:80 nginx:alpine
6e5b52fae13a6669da0f87d96aef38ec02661df05e5a646eeeb00417b47ad2d5
启动容器时,如果本地没有所用的镜像则会自动下载, 一般而言执行完docker run命令后返回生成容器的ID
6.查看正在运行的容器: docker ps
展示结果的第一列是容器的ID(唯一), 最后一列NAMES是容器的名字(唯一)
Usage: docker ps [OPTIONS]
List containers
Options:
-a, --all Show all containers (default shows just running)
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print containers using a Go template
-n, --last int Show n last created containers (includes all states) (default -1)
-l, --latest Show the latest created container (includes all states)
--no-trunc Don't truncate output
-q, --quiet Only display numeric IDs
-s, --size Display total file sizes
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6e5b52fae13a nginx:alpine "nginx -g 'daemon of…" About a minute ago Up About a minute 0.0.0.0:18000->80/tcp nginx
可以看到nginx容器正在运行,监听宿主机的18000端口
我们可以通过访问 宿主机IP:18000 就可以访问到容器的nginx
curl http://10.93.181.200:18000/index.html
Welcome to nginx!
Welcome to nginx!
If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.
For online documentation and support please refer to
nginx.org.
Commercial support is available at
nginx.com.
Thank you for using nginx.
查看所有的容器命令: docker ps -a
容器启动失败,就会自动停止,此时就需要使用上面的命令找到已停止的容器
7.查看容器日志: docker logs
Usage: docker logs [OPTIONS] CONTAINER
Fetch the logs of a container
Options:
--details Show extra details provided to logs
-f, --follow Follow log output 实时跟踪显示,类似tail -f
--tail string Number of lines to show from the end of the logs (default "all")
-t, --timestamps Show timestamps
--until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
# 实时查看nginx 容器的日志
docker logs -f 6e5b52fae13a
8.容器启停: docker start/stop containerID
9.进入容器: docker attach
和docker exec
docker attach containerID 可以进入当前容器运行的终端,如果从这个终端中 exit,会导致容器的停止。
所以一般都是用exec的方式
Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
Run a command in a running container
Options:
-d, --detach Detached mode: run command in the background
--detach-keys string Override the key sequence for detaching a container
-e, --env list Set environment variables
-i, --interactive Keep STDIN open even if not attached
--privileged Give extended privileges to the command
-t, --tty Allocate a pseudo-TTY
-u, --user string Username or UID (format: [:])
-w, --workdir string Working directory inside the container
# 启动一个 sh 终端进入容器(只能进入正在运行的容器)
docker exec -it 6e5b52fae13a bash
如果使用以上命令进入容器报错:
OCI runtime exec failed: exec failed: container_linux.go:344: starting container process caused "exec: \"bash\": executable file not found in $PATH": unknown
还可以使用:docker exec -it 6e5b52fae13a /bin/sh
docker cp
Usage: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
Copy files/folders between a container and the local filesystem
Options:
-a, --archive Archive mode (copy all uid/gid information)
-L, --follow-link Always follow symbol link in SRC_PATH
# 1.将宿主机的文件拷贝进容器内
# 在宿主机创建foo.txt文件并拷贝到容器内
echo "bar" > foo.txt
docker cp foo.txt nginx:/tmp
# 然后再容器内查看tmp目录
ls -ltr /tmp/
total 4
-rw-r--r-- 1 root root 4 Jul 8 11:02 foo.txt
# 2.将容器内的文件拷贝到宿主机外
# 先在容器内创建文件
echo "a" > b.txt
# 然后再在宿主机执行命令把容器拷贝出来
docker cp nginx:/tmp/b.txt ./
ls b.txt #文件存在
docker inspect
Usage: docker inspect [OPTIONS] NAME|ID [NAME|ID...]
Return low-level information on Docker objects
Options:
-f, --format string Format the output using the given Go template
-s, --size Display total file sizes if the type is container
--type string Return JSON for specified type
# 使用 docker inspect命令查看镜像详细信息
docker inspect nginx:alpine
# 使用 docker inspect命令查看容器详细信息
docker inspect CONTAINER_ID
12.镜像与tar文件的转换, 镜像导入docker load
、导出docker save
Usage: docker save [OPTIONS] IMAGE [IMAGE...]
Save one or more images to a tar archive (streamed to STDOUT by default)
Options:
-o, --output string Write to a file, instead of STDOUT
# 导出nginx镜像到当前目录的 nginx-image.tar
docker save -o nginx-image.tar nginx:alpine
---------------------------------------------------------------------------
Usage: docker load [OPTIONS]
Load an image from a tar archive or STDIN
Options:
-i, --input string Read from tar archive file, instead of STDIN
-q, --quiet Suppress the load output
# 导入镜像
docker load -i nginx-image.tar
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了构建镜像所需的指令和说明
常用指令
FROM
指定base镜像,基于基础镜像进行构建
COPY
将文件从build context 复制到镜像
ADD
与COPY类型,从build context复制文件到镜像,不同的是如果是标准压缩文件(tar,zip,tgz,xz),那么文件会被自动解压。
ENV
设置环境变量,在Dockerfile中使用,在构建过程中有效,在image被创建和container启动后作为环境变量依旧也有效,并且可以重写覆盖。
ARG
在Dockerfile中使用,仅在build docker image的过程中(包括CMD和ENTRYPOINT)可用,在image被创建和container启动之后不可用。
RUN
在容器执行执行命令,每一个 RUN 都是启动一个容器、执行命令、然后提交存储层文件变更
WORKDIR
为RUN,CMD,ENTRYPONT,ADD或COPY 指令设置镜像中的当前工作目录
EXPOSE
指定容器容器中的进程会监听某个端口,Docker可以将该端口暴露出来
VOLUME
将文件或者目录声明为volume
CMD
容器启动时运行指定的命令,Dockerfile中可以有多个CMD指令,但是只有最后一个生效;CMD 可以被docker run 后面的参数替换
ENTRYPONT
设置容器启动时运行的命令,Dockerfile中可以有多个ENTRYPONT指令,但是只有最后一个生效;ENTRYPONT可以被docker run 后面的参数会传递给ENTRYPONT 作为参数执行(可以自行了解)。
dockerfile实战-构建简单SpringBoot应用镜像
FROM openjdk:8-jdk-alpine
# 配置同级目录下jar包名字
ENV JAR_NAME=awesomejava-0.1.jar
# 工作目录/opt,jar包会被复制为/opt/app.jar
WORKDIR /opt
COPY $JAR_NAME app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/opt/app.jar"]
使用docker build命令构建镜像
docker build --force-rm=true --no-cache=true -t awesome-java:0.1 -f Dockerfile ./
–force-rm=true 删除RUN指令的创建中间容器
-t awesome-java:0.1 指定本次构建的镜像名为 awesome-java:0.1
-f Dockerfile 指定dockerfile文件
./ build context 为当前目录,执行构建命令时,docker client 会将当前目录的所有文件发
送到服务端 daemon 的临时目录,然后按照dockerfile指令一层一层构建
镜像导出:
docker save awesome-java:0.1 | gzip > awesome-java:0.1.tar.gz
Docker教程|菜鸟教程
Docker — 从入门到实践