原创做者,公众号【程序员读书】,欢迎关注公众号,转载文章请注明出处哦。mysql
镜像(Image)
,容器(Container)
,仓库(Repository)
是咱们常说的Docker
的三大组件,其实咱们在上一篇文章《10分钟快速掌握Docker必备基础知识》已经有简单地了解过三大组件的知识,可是并无很详细地讲解,因此在这篇文章中,咱们就来一块儿详细地探索一番吧。nginx
什么是Docker
镜像?程序员
简单地理解,Docker镜像
就是一个Linux
的文件系统(Root FileSystem
),这个文件系统里面包含能够运行在Linux内核
的程序以及相应的数据。web
谈到这里,咱们可能须要先补充一点与Linux
操做系统相关的知识:redis
通常而言,
Linux
分为两个部分:Linux内核(Linux Kernel)
与用户空间
,而真正的Linux操做系统
,是指Linux内核
,咱们经常使用的Ubuntu
,Centos
等操做系统实际上是不一样厂商在Linux内核
基础上添加本身的软件与工具集(tools
)造成的发布版本(Linux Distribution
)。sql
所以,咱们也能够把镜像当作是上面所说的用户空间
,当Docker
经过镜像建立一个容器时,就是将镜像定义好的用户空间
做为独立隔离的进程运行在宿主机的Linux内核
之上。docker
这里要强调一下镜像的两个特征:编程
镜像是分层(Layer
)的:即一个镜像能够多个中间层组成,多个镜像能够共享同一中间层,咱们也能够经过在镜像添加多一层来生成一个新的镜像。centos
镜像是只读的(read-only
):镜像在构建完成以后,便不能够再修改,而上面咱们所说的添加一层构建新的镜像,这中间实际是经过建立一个临时的容器,在容器上增长或删除文件,从而造成新的镜像,由于容器是能够动态改变的。安全
经过下面的示意图,我能够更好地理解Docker镜像
与Linux
的关系:
Docker
中与镜像操做相关的命令都在docker image
这条子命令下,经过docker image --help
这条命令,能够看到docker image
子命令的详细文档,以下:
Usage: docker image COMMAND
Manage images
Commands:
build Build an image from a Dockerfile(构建镜像的命令)
history Show the history of an image(显示镜像构建历史过程)
import Import the contents from a tarball to create a filesystem image(导入一个由容器导出的镜像)
inspect Display detailed information on one or more images(显示一个镜像的详细信息)
load Load an image from a tar archive or STDIN(从一个文件或标准输入流中导入镜像)
ls List images(查看镜像列表)
prune Remove unused images(删除虚悬镜像)
pull Pull an image or a repository from a registry(从仓库拉取镜像)
push Push an image or a repository to a registry(推送镜像到仓库)
rm Remove one or more images(删除镜像)
save Save one or more images to a tar archive (streamed to STDOUT by default)(保存镜像到文件)
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE(给镜像打标签)
复制代码
在安装了Docker
以后,咱们本地并无任何镜像,固然咱们能够本身构建,不过更方便仍是从Docker
官方提供的仓库服务Docker Hub
上拉取官方或第三方已经构建好的镜像。
拉取镜像可使用docker image pull
,其格式以下:
docker image pull [OPTIONS] NAME[:TAG|@DIGEST]
复制代码
固然,docker image pull
有更简洁的用法:如:
docker pull [OPTIONS] NAME[:TAG|@DIGEST]
复制代码
要拉取镜像,须要指定Docker Registry
的URL和端口号,默认是Docker Hub
,另外还须要指定仓库名
和标签,仓库名和标签惟一肯定一个镜像,而标签是可能省略,若是省略,则默认使用latest
做为标签名,而仓库名则由做者名和软件名组成。
因此,在省略了那么参数后,好比咱们想拉取centos
镜像,可使用下面简单的命令从Docker Hub
上拉到:
$ docker pull centos
复制代码
经过上面的方法咱们将镜像拉取到了本地,那要如何查看本地有哪些镜像呢?经过下面的命令咱们能够查看本地的所有镜像:
$ docker image ls
复制代码
固然Docker
提供了更简洁的写法,以下:
$ docker images
复制代码
咱们知道Docker
镜像名由仓库名
和标签
组成,但有时候咱们会看到仓库名和标签皆为<none>
的镜像,咱们称为这种镜像为虚悬镜像
,以下图所示:
虚悬镜像
通常是当咱们使用docker pull
拉取最新镜像时,生成的新的镜像,因此仓库名
和标签
给了新的镜像,旧的镜像仓库和标签则被取消,成为虚悬镜像
。
咱们可使用下面的语句打印全部的虚悬镜像
:
$ docker image ls -f dangling=true
复制代码
通常的虚悬镜像已经没有什么做用了,因此能够清理掉的,下面的命令能够清除全部的虚悬镜像:
$ docker image prune
复制代码
不过,若是咱们想保留一些有用的虚拟镜像时,可使用docker tag
命令从新给镜像起个仓库名和标签:
$ docker tag 621d57f27e93 "test:1.0"
复制代码
若是想与别人共享某个镜像,除了从镜像服务仓库中pull
镜像和把镜像push
到仓库上去以外,其实咱们还能够将本地构建好的镜像直接导出并保存为文件发送给别人,以下:
$ docker image save -o /tmp/test_image.tar.gz centos:latest
复制代码
而当你拿到别人导出的镜像文件,你可使用docker load
命令把镜像加载到本地的Docker
镜像列表中,以下:
$ docker load < /tmp/test_image.tar.gz
复制代码
要删除一个或多个本地的镜像,可使用下面的命令:
docker image rm [option] IMAGE1,IMAGE2,...IMAGEn
复制代码
也可使用更简洁的方式,如:
docker rmi [option] IMAGE1,IMAGE2,...IMAGEn
复制代码
可使用镜像的长id、镜像短id、镜像摘要以及镜像名称来删除镜像,以下
$ docker rmi f7302e4ab3a8
复制代码
通常更经常使用镜像的短id,如:
$ docker rmi f7302
复制代码
使用镜像的摘要也能够删除镜像,镜像的摘要可使用下面的命令查询:
$ docker image ls --digests
复制代码
固然咱们想要清除本地所有镜像时,可使用下面的命令,不过通常不建议使用。
$ docker rmi $(docker images -qa)
复制代码
另外,通常若是镜像已经被使用来建立容器,使用上面的命令删除会报下面的错误,告诉咱们该镜像已经被使用,不容许删除。
Error response from daemon: conflict: unable to remove repository reference "mysql:5.7" (must force) - container ccd406c07a78 is using its referenced image e1e1680ac726
复制代码
对于已经被用于建立容器的镜像,删除方法有两种,一种是先把容器删除,再删除镜像,另外一种则只须要在删除镜像的命令中跟一个-f
参数即可,如:
$ docker rim -f f7302
复制代码
上面的例子都是直接使用官方提供的镜像,其实,除了从官方仓库或其余镜像仓库拉取别人构建好的镜像外,咱们也能够构建本身的镜像,通常有如下两种构建方式。
使用docker commit
命令,咱们能够将修改过的容器从新提交为一个镜像,如:
$ docker commit conntaner_id my-hello:1.0
复制代码
使用这种方式构建的镜像,咱们称为黑箱镜像,就是一个黑箱子同样,别人并不知道咱们对容器作了哪些修改和操做,因此会对其安全性有所质疑。
因此不推荐使用这种方式构建镜像,下面咱们介绍一种更加通用且方便的方式。
Dockerfile
构建镜像通常推荐编写Dockerfile
来构建一种镜像,Docker Hub
上的镜像都是采用这种方式构建的,采用这种方式的好处就是,咱们不用把镜像分发给别人,而只是把Dockerfile
和相应须要写入镜像的资料发给别人,别人也能本身构建镜像,安全透明。
package main
import "fmt"
func main(){
fmt.Println("Hello Go")
}
复制代码
将Go
程序编译为可执行程序,如:
$ go build hello.go
复制代码
Dockerfile
文件下面咱们编写一个简单的Dockerfile
文件,构建本身的第一个镜像,以下:
# 从一个空白的镜像开始
FROM stratch
ADD hello /
# 执行
CMD /hello
复制代码
编写好Dockerfile
文件后,须要使用docker build
命令进行构建,docker build
命令的格式以下:
$ docker build [OPTIONS] PATH | URL | -
复制代码
# 注意最后的点(.)表示当前目录,即Dockerfile所在的目录
$ docker build -t "hello-go:1.0" .
复制代码
上面只是简单演示了使用Dockerfile
文件如何构建镜像,关于Dockerfile
,还有许多更加深刻地用法,咱们以后有机再谈。
容器与镜像的关系,就如同面向编程中对象与类之间的关系。
由于容器是经过镜像来建立的,因此必须先有镜像才能建立容器,而生成的容器是一个独立于宿主机的隔离进程,而且有属于容器本身的网络和命名空间。
咱们前面介绍过,镜像由多个中间层(layer)组成,生成的镜像是只读的,但容器倒是可读可写的,这是由于容器是在镜像上面添一层读写层(writer/read layer)来实现的,以下图所示:
Usage: docker container COMMAND
Manage containers
Commands:
attach Attach local standard input, output, and error streams to a runnin g container
commit Create a new image from a container's changes(把容器保存为镜像) cp Copy files/folders between a container and the local filesystem create Create a new container(建立一个新的容器) diff Inspect changes to files or directories on a container's filesyste m
exec Run a command in a running container(在一个运行的容器中执行命令)
export Export a container's filesystem as a tar archive inspect Display detailed information on one or more containers kill Kill one or more running containers(杀死一个或多个正在运行的容器) logs Fetch the logs of a container ls List containers(显示本地容器列表) pause Pause all processes within one or more containers port List port mappings or a specific mapping for the container prune Remove all stopped containers rename Rename a container(重命名容器) restart Restart one or more containers(重启一个或多个容器) rm Remove one or more containers(删除一个或多个容器) run Run a command in a new container(运行一个新的容器) start Start one or more stopped containers stats Display a live stream of container(s) resource usage statistics stop Stop one or more running containers(中止一个或多个容器) top Display the running processes of a container unpause Unpause all processes within one or more containers update Update configuration of one or more containers wait Block until one or more containers stop, then print their exit codes 复制代码
启动容器有几种不一样的方式,最经常使用的方法是使用docker run
命令能够经过镜像建立一个容器,如:
# /bin/bash表示运行容器后要执行的命令
$ docker run -it centos /bin/bash
复制代码
docker run
命令有一些比较经常使用的参数,好比容器是一种提供服务的守护进程,那么一般须要开放端口供外部访问,如:
$ docker run -p 80:80 nginx
复制代码
也能够为容器指定一个名称,如:
$ docker run -p 80:80 --name webserver nginx
复制代码
另一种则是使用docker start
命令从新启动已经中止运行的容器,如:
# container_id表示容器的id
$ docker start container_id
复制代码
而对于正在运行的容器,也能够经过docker restart
命令从新启动,如:
# container_id表示容器的id
$ docker restart container_id
复制代码
运行容器后,咱们能够经过下面的命令查看本地全部容器:
$ docker container ls
复制代码
不过docker container ls
也简洁的写法:
$ docker ps
复制代码
上面命令执行结果以下:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f4f184f5ffb9 redis:latest "docker-entrypoint.s…" 6 seconds ago Up 4 seconds 0.0.0.0:6379->6379/tcp myredis
f7d970e7d4ce mysql:5.7 "docker-entrypoint.s…" 7 seconds ago Up 5 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp docker-mysql
复制代码
上面的命令只会显示正在运行的容器,若是要显示所有容器,包含退出执行的,能够加参数-a
,如:
$ docker ps -a
复制代码
有时候,咱们只想查到容器的id,能够用下面的命令:
$ docker ps -aq
复制代码
执行结果
f4f184f5ffb9
f7d970e7d4ce
复制代码
对于已经不须要的容器,可使用docker stop
命令中止其运行,如:
$ docker stop container_id1,container_id2...
复制代码
批量中止容器,如:
$ docker stop $(docker ps -qa)
复制代码
归纳而言,Docker
容器大致上有三种运行模式,以下:
下面语句建立的容器,在运行后会退出。
$ docker run centos echo "hellowrold"
复制代码
若是容器中运行一个守护进程,则容器会一直处于运行状态,如:
$ docker run -d -p 80:80 nginx
复制代码
咱们也能够在运行容器时,直接与容器交互。
$ docker run -it centos /bin/bash
复制代码
$ docker container rm container_id
复制代码
删除容器的命令也有简洁的写法,以下:
$ docker rm container_id
复制代码
也能够像上面批量中止容器同样,咱们也能够批量删除容器,如:
$ docker rm $(docker ps -qa)
复制代码
对于正在运行的容器,咱们也能够经过docker exec
命令再次进入容器,如:
$ docker exec -it f4f184f5ffb9 /bin/bash
复制代码
须要指定容器的id或name,上面的命令咱们用的是id。
$ docker export -o ./image.tar.gz f4f184f5ffb9
复制代码
将容器导出后,咱们能够另一台有安装Docker
的电脑中将文件包导入成为镜像,如:
$ docker import image.tar.gz
复制代码
上面讲的是容器的概念和一些经常使用的命令,关于容器,还能够设置数据卷和网络空间,这些咱们有机会后面再谈。
仓库(Repository
)是集中存储镜像的地方,这里有个概念要区分一下,那就是仓库与仓库服务器(Registry
)是两回事,像咱们上面说的Docker Hub
,就是Docker
官方提供的一个仓库服务器,不过其实有时候咱们不太须要太过区分这两个概念。
公共仓库通常是指Docker Hub
,前面咱们已经屡次介绍如何从Docker Hub
获取镜像,除了获取镜像外,咱们也能够将本身构建的镜像存放到Docker Hub
,这样,别人也可使用咱们构建的镜像。
不过要将镜像上传到Docker Hub
,必须先在Docker
的官方网站上注册一个帐号,注册界面以下,按要求填写必要的信息就能够注册了,很简单的。
注册好了以后,能够在本地使用命令登陆到Dokcer Hub
了,过程以下:
# 在命令行中输入
$ docker login
复制代码
在输入帐号密码登陆到Docker Hub
以后,即可以使用docker push
命令把镜像推送到Docker Hub
。
$ docker push test:1.0
复制代码
有时候本身部门内部有一些镜像要共享时,若是直接导出镜像拿给别人又比较麻烦,使用像Docker Hub
这样的公共仓库又不是很方便,这时候咱们能够本身搭建属于本身的私有仓库服务,用于存储和分布咱们的镜像。
Docker
官方提供了registry
这个镜像,能够用于搭建私有仓库服务,咱们把镜像拉到本地以后,用下面命令建立该镜像的容器即可以搭建一个仓库服务,以下:
$ docker run -d -p 5000:5000 --restart=always --name registry registry
复制代码
假设咱们把一台IP为192.168.0.100
的服务器做为仓库服务,并运行上面的语句,那么咱们能够下面的语句从新构建上面的镜像,如:
$ docker build -t "192.168.0.100/hello-go:1.0" .
复制代码
而后使用下面的语句推送到本身的私有仓库服务器:
$ docker push 192.168.0.100/hello-word:1.0
复制代码
镜像是静态的概念,构建完成以后便不能再修改,而容器则是一个动态的概念,使用Docker
能够简单轻松地建立或删除容器,镜像与容器的关系,就如同面向对象编程中的类与对象的关系,而仓库则是存储和分发镜像的地方。
欢迎扫码关注,共同窗习进步