如果我们想要让软件运行起来,首先要保证操作系统的设置,其次还需要依赖各种组件和库的正确安装。那么虚拟机就是一种带环境安装的一种解决方案,它可以实现在一种操作系统里面运行另外一种操作系统,但是虚拟机的缺点也是十分明显的,资源占用多、冗余步骤多、启动速度慢。由于虚拟机存在的这些令人诟病的缺点。Linux发展出了另一种虚拟化技术,Linux Containers,即Linux容器,缩写为LXC。
Linux容器并没有虚拟一个完整的操作系统,而是对进程进行隔离。或者说,在正常进程的外面套了一层保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。Linux的容器也十分明显,体积小、启动快、资源占用也是极少的。
Docker属于Linux容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的Linux容器解决方案。Docker将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里面运行,就好像在真实的物理机上运行一样。
同时Docker的应用场景也十分广泛,比如:单项目打包、整套项目打包、新开源技术、环境一致性、持续集成、微服务、弹性伸缩等。
下面我们来看一张图,来学习下Docker体系的结构:
我们看上图哦,Docker通过Docker Client的客户端发送指令,驱动Docker Engine引擎来启动容器,然后通过Containerd来管理对应容器的内容,然后,shim只用来管理每个独立的容器,通过runC这个轻量级的工具来启动容器。在启动容器的时候,可能会去Image Repository镜像仓库中去取对应的依赖。
Docker提供了一些内部的组件,我们也需要了解一下:
- namespaces,命名空间,Linux内核提供的一种对进程资源隔离的机制,例如进程、网络、挂载等资源。
- cgroups,控制组,linux内核提供的一种限制进程资源的机制,例如cpu、内存等资源。
- unonFS,联合文件系统,支持将不同位置的目录挂载到同一虚拟文件系统中,形成一种分层的模型。
首先docker的版本类型上,分为企业版和社区版,咱们用社区版就可以了,企业版是付费的。它的安装文档地址在:https://docs.docker.com/engine/install/centos/。
我们通过下面的命令来安装下docker:
先安装docker的一些依赖:
yum install -y yum-utils device-mapper-persistent-data lvm2
再安装docker的安装源:
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
最后安装docker:
yum install docker-ce docker-ce-cli containerd.io -y
这样,我们的docker就安装好了。然后我们看下常用的一些命令:
# 启动docker systemctl start docker # 查看docker信息 docker version docker info # 卸载docker yum remove docker # 删除docker相关的文件夹 rm -rf /var/lib/docker
我们也可以把相关的软件依赖改成阿里云的镜像地址,这样下载的时候会快一些,我就不多说了,因为我没改:
# 创建一个文件 sudo mkdir -p /etc/docker # 写入一些配置 sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://fwvjnv59.mirror.aliyuncs.com"] } EOF # 重载所有修改过的配置文件 # daemon-reload: 重新加载某个服务的配置文件 sudo systemctl daemon-reload sudo systemctl restart docker三、Docker镜像
Docker把应用程序及其依赖,打包再image镜像文件里面,只有通过这个文件,才能生成Docker容器。image镜像文件可以看作是容器的模板。Docker根据image镜像文件生成容器的实例。同一个image镜像文件,可以生成多个同时运行的image实例。镜像文件不是一个单一的文件,而是有多层次的结构。容器其实就是在image镜像的最上面一层加了一层读写层。在运行容器里做的任何文件改动,都会写到这个读写层里。如果容器删除了,最上面的读写层也就删除了,改动也就丢失了。
我们可以通过docker history [id/name] 查看镜像中各层级的内容及大小,每层对应着dockerfile中的一条指令。
下面我们来学习下一些基本的命令:
- docker image ls,查看全部镜像。字段含义如下: REPOSITORY 仓库地址 TAG 标签 IMAGE_ID 镜像ID CREATED 创建时间 SIZE 镜像大小
- docker search [imageName],查找镜像。字段含义如下:
字段 含义 NAME 名称 DESCRIPTION 描述 STARTS 星星的数量 OFFICIAL 是否官方源 - docker history [imageName],查看镜像历史。
- docker inspect [imageName],显示一个或多个镜像信息。
- docker pull [imageName],拉取镜像。
- docker push [imageName],推送一个镜像到镜像仓库。
- docker rmi [imageName],删除镜像。
- docker image prune,移除未使用的镜像,没有标记或被任何容器引用。
- tag,标记本地镜像,将其归入某一仓库
- 语法:docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]。
- 例子:docker tag centos:7 zaking/centos:v1。
- export,将容器文件系统作为一个tar归档文件导出到STDOUT。
- 语法:docker export [OPTIONS] CONTAINER。
- docker export -o hello-world.tar b2712f1067a3。
- import,导入容器快照文件系统tar归档文件并创建镜像。
- 语法:docker import [OPTIONS] file/URL/- [REPOSITORY[:TAG]。
- 例子:docker import hello-world.tar。
- save,将指定文件保存成tar文件。
- 语法:docker save [OPTIONS] IMAGE [IMAGE...]。
- docker save -o hello-world.tar hello-world:latest。
- load,加载tar文件并创建镜像。
- 例子:docker load -i hello-world.tar。
- build,根据Dockerfile构建镜像。
- 语法:docker build [OPTIONS] PATH / URL / -。
- 例子:docker build -t zf/ubuntu:v1。
然后,我们学习了一些相关的命令,下面我们来拿这些命令做一些实践:
首先,我们查找一下centos镜像:
docker search centos
然后,我们把centos的镜像拉取到本地,如果你这里下载很慢的话,请回头安装阿里源,嘻嘻:
docker pull centos
然后,我们可以使用fs命令,查看下现在有哪些镜像:
docker image ls
下一步我们从远程镜像仓库拉取一个docker官方的例子镜像到本地的镜像仓库:
docker pull docker.io/hello-world
然后,可以通过rmi命令,删除本地镜像:
docker rmi hello-world
四、Docker容器
首先,我们来学习下一些有关于容器的基本概念。docker run 命令会从image镜像文件中生成一个正在运行的容器实例。该命令具有自动抓取image镜像文件的功能,如果发现本地没有指定的image文件,就会从仓库自动抓取。输出提示后,实例就会停止运行,容器自动终止,当然,并不是所有的容器都会自动终止。同过image镜像文件生成的生成的容器实例,本身也是一个文件,成为容器文件。生成了容器后,就会同时存在两个文件,image镜像文件和容器文件。关闭容器并不会删除容器文件,只是停止容器的运行。
下面,我们来学习一下容器有关的命令:
- docker run:启动容器。
- 例子:docker run ubuntu /bin/echo 'hello world'。这句话的意思就是,通过ubuntu镜像生成一个容器,在容器中执行/bin/echo 'helloworld'的命令。我们看下图,当我们想要执行的命令在容器中打印后,该容器就自动终止了。这就是我们上面说到的含义。另外,如果本地没有对应的镜像,docker会自动去docker hub拉取。
- 参数:
- -i,--interactive:交互式。
- -t,-tty:分配一个伪终端。
- -d,--detach:运行容器到后台。
- -a,--attach list:附加到运行的容器。
- -e,--env list:设置环境变量。
- -p,--publish list:发布容器端口到主机。
- -P,--publish-all:。
- docker ps:查看容器。
- 参数:
- -a:显示所有的容器,包括已停止的。
- -l:显示最新的那个容器。
字段 含义 CONTAINER ID 容器ID IMAGE 使用的镜像 COMMAND 使用的命令 CREATED 创建时间 STATUS 状态 PORTS 端口号 NAMES 自动分配的名称
- 参数:
- docker run -i -t ubuntu /bin/bash:运行交互式的容器。可以通过exit命令或CTRL+D退出交互界面。
- -t=--interactive 在新容器内指定一个伪终端或终端。
- -i=--tty 允许你对容器内的标准输入 (STDIN) 进行交互。
- docker kill:kill是不管容器同不同意,直接执行
kill -9
,强行终止;stop的话,首先给容器发送一个TERM
信号,让容器做一些退出前必须的保护性、安全性操作,然后让容器自动停止运行,如果在一段时间内,容器还是没有停止,再进行kill -9,强行终止。
- 例子:docker kill 5a5c3a760f61。
- docker rm:删除容器。
- 例子:docker rm 5a5c3a760f61。
- docker rm $(docker ps -a -q)。删除所有的容器,-a,所有的,-q显示id号。就是批量删除所有的意思。
- docker start [containerId]:启动容器。
- docker stop [containerId]:停止容器。
- docker attach [containerID]:进入一个容器。
- docker container -exec -it [containerID] /bin/bash:进入一个正在进行中的容器。
- docker container cp [containerID]/readme.md .:拷贝文件。
- docker run --rm ubuntu /bin/bash:自动删除。
- docker container stats:显示容器资源使用统计。
- docker container top:显示一个容器运行的进程。
- docker update -m 500m 6d1a25f95132:更新一个或多个容器配置。
- 列出指定的容器的端口映射:
docker run -d -p 8080:80 nginx docker container port containerID
-
docker logs [containerId]:查看docker容器的输出。
下面,我们把上面学习的命令来实践一下:
刚才我们在学习run命令的时候已经启动了一个容器并打印出了命令,那个是最基础的方法,那下面,我们来查看下我们的容器都有哪些:
docker ps -a
哈,只有一个,就是我们刚才执行的那个。下面我们来试一下启动一个交互式的容器:
docker run -i -t ubuntu /bin/bash
我们就进入了交互式容器的伪终端里,可以进行命令交互。然后我们执行下面的命令:
docker run centos ping www.baidu.com
执行了这个命令后,就会一直ping www.baidu.com,别的事就干不了了,只能看着:
此时,我们就需要--detach参数,进入后台运行:
docker run --detach centos ping www.baidu.com
然后,这个容器就会在后台运行:
那,我想要查看这个容器里面的日志怎么办呢,通过下面的命令就可以查看对应容器里的日志了:
docker logs --follow [id/name]
当然,我们也可以通过attach,重新进入这个容器。
docker attach [id]
然后,可以通过stop命令,停止某个正在运行中的容器:
docker stop [containerId]
docker stop是否能停止,是由容器内部指定的,需要运行完一些必要的容器才会停止。如果你希望可以立即杀死该容器,直接强行终止,就使用kill命令。停止了以后,我们可以通过docker start来重新启动。
然后,我们可以通过rm命令,删除已有的容器:
docker ps -a
先通过ps命令看下目前容器的id,然后通过rm删除:
docker rm [id]
这样一个一个删除太慢了,我们可以通过下面的命令批量删除:
docker rm $(docker ps -a -q)
很简单吧。
1、其它命令实践:
下面我们来练习下其他命令,我们先启动个hello-world的容器:
docker run hello-world
然后我们把这个容器导出:
docker export -o hello-world.tar [cantainerId]
然后我们看下这个文件:
删除这个容器:
docker rm [containerId]
然后镜像文件也删除掉:
docker rmi hello-world
然后,我们可以通过import命令,把刚才导出的tar包,再导入回来:
docker import hello-world.tar
就是这个了。
save命令可以把指定镜像打包成tar文件:
docker save -o redis.tar redis:latest
然后删除你刚才打包成tar的镜像,怎么删除我就不说了啊。删除了之后,我们可以通过load命令,把刚才的tar包下载回来。
docker load -i redis.tar
用户既可以使用 docker load
来导入镜像存储文件到本地镜像库,也可以使用 docker import
来导入一个容器快照到本地镜像库。这两者的区别在于容器(import)快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像(load)存储文件将保存完整记录,体积也要大。此外,从容器(import)快照文件导入时可以重新指定标签等元数据信息。
2、下面我们来实践一些容器相关的:
我们先后台跑起来前面的那个ping命令:
docker run --detach centos ping www.baidu.com
然后,我们来用stats看下它的状态:
docker stats [containerId]
然后可以通过top命令,查看一个运行中容器的进程:
docker top [containerId]
我们还可以使用update命令更新一个或多个容器的配置,看stats那个图,LIMIT是1.7G左右,我们来通过update命令,限制一下它的内存:
docker update -m 500m [containerId]
可惜报错了,他跟你说还要同时设置memoryswap,设置一下呗:
然后LIMIT就变成了500M,简单吧。
3、下面我们来实践下如何映射指定容器的端口:
先使用下面的命令,启动一个docker容器中的nginx:
docker run -d -P nginx
这样会自动指定与宿主机的端口映射。
图中红框的部分就是自动指定的与宿主机的映射,我们也可以手动设置:
docker run -d -p 8080:80
这个意思就是说宿主机的ip是8080端口映射到docker容器的nginx的80端口。
4、学习下如何commit命令制作个性化镜像:
我们先停止并删除之前所有的容器:
docker stop $(docker ps -a -q) docker rm $(docker ps -a -q)
然后像之前的例子一样,启动一个nginx容器。
通过下面的命令进入到容器的伪终端中:
docker exec -it [containerId]/bin/bash
然后,我们进入到容器的nginx存储html文件的目录,/usr/share/nginx/html:
cd /usr/share/nginx/html
创建一个html文件:
echo hello > hello.html
然后我们再打开一个命令行,访问一下刚才的nginx服务,要注意查看端口号哦:
这样就成功了。下面看下如何基于这个容器,建一个新的镜像:
docker commit -m'zakings nginx' -a'zaking' 0a90e57ca86b zaking/zakingnginx
这段代码是什么意思呢,docker commit -m'描述信息' -a'作者信息' [containerId] [包名]。
我们可以查看下:
多了我们刚才生成的镜像。下面我们清空下容器,使用我们自己创建的镜像创建容器:
不多说了,实践好多遍了。
然后呢,实际上就是跟之前的方式一样,创建nginx容器,并自动设置端口号就好了:
docker run -d -P [你自己刚才生成的镜像名字]
然后,在另一个终端访问下:
直接就出来了,不需要我们再重新创建了。当然,如果要发布到远程仓库,需要注册账号。这个我就不多说了,大家有兴趣可以自己试一下。
好啦,关于容器和镜像的部分。就先到这里了。
站在巨人的肩膀上,希望我可以看的更远。