简单易懂的Docker基础知识

时间:2022-07-24
本文章向大家介绍简单易懂的Docker基础知识,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

虚拟化和云计算已经是一个很火热技术话题了,基于虚拟化技术,我们可以实现对硬件资源的充分利用,实现对软件运行环境的隔离。但是传统的虚拟化技术,基本都是通过虚拟一个个单独的操作系统来实现虚拟化的需求。这虽然在一定程度上增加了硬件资源的利用率,但是这样的虚拟化解决方案,有时却显得不是那么聪明,在许多场景下依然显得很笨重,相比于应用软件的开销,有可能虚拟机系统的开销比应用本身还要高。所以,在一些轻量化的场景下,当前的虚拟化技术就无法很好的发挥其作用了。这个问题随着Docker的出现,拥有了更为完美的解决方案。

Docker是基于LXC虚拟化技术实现的新型虚拟化技术,其核心思想,在我个人理解来看,就是将开发人员的代码需要的依赖环境作为虚拟化的“单位”,至于操作系统,所有的“单位”都共用宿主机的操作系统。而这一个个的“单位”就是一个个的docker,即所谓的容器。用户可以将这些依赖,环境等打包起来,制作成一个模板,方便迁移,而这个模板就是所谓的镜像,通过镜像,用户可以很方便的制作出一个个的容器。而这些镜像如何管理呢?很明显,我们可以将这些镜像放在一个固定的地方,我们每当要用的时候都去这个地方取就好了,这个地方就叫镜像仓库。

Docker的设计思想和面向对象的思想很类似,镜像就相当于一个类,一个容器就相当于用这个类实例化出来的具体实例。

Docker安装

本文基于Centos系统安装部署Docker,其他操作系统的部署方法还请百度。需要注意的是,我们需要Centos系统的内核版本高于3.8,所以,我们采用Centos7.7版本的操作系统。

安装之前,我们先要通过yum安装一些基础的yum源,如epel等,此处不再赘述,安装完成后,我们来安装docker的yum源:

$ yum install -y yum-utils
$ yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

此处我们可以看到,我们安装了一个阿里云提供的yum源,此处需要说明一下,自2017年3月2号,Docker团队发布了Docker EE版和Docker CE版,即企业版和社区版。而且,Docker团队还更改了社区版的版本号命名规则,在此之前,Docker一致遵循大小版本号的规范,自此之后,Docker改为使用时间的方式来作为版本号,比如2017年3月2日发布的第一个CE版本的版本号是17.03,Docker官方每个季度都会更新一个季度版本,也就是一年内会有4个版本。

从上图中,我们可以看到,截至当前,阿里云的yum源中更新到了19.03.4这个版本,我们使用yum来安装:

$ yum -y install docker-ce

安装完成后,我们需要准备一下docker的配置文件及创建相关的目录:

$ mkdir /etc/docker
$ vim /etc/docker/daemon.json
$ cat /etc/docker/daemon.json 
{
  "graph": "/data/docker",                     # docker相关文件的存放目录
  "storage-driver": "overlay2",                # docker的存储驱动
  "insecure-registries": ["registry.access.redhat.com","quay.io"],     # 私有仓库地址
  "registry-mirrors": ["https://q2gr04ke.mirror.aliyuncs.com"],        # 加速地址
  "bip": "172.7.5.1/24",                       # docker容器的IP地址段
  "exec-opts": ["native.cgroupdriver=systemd"],
  "live-restore": true
}
$ mkdir -p /data/docker

创建完成配置文件后,我们就可以启动docker了:

$ systemctl enable docker
$ systemctl start docker

至此,我们的Docker服务就已经安装完成了。接下来我们来学习一些Docker命令。

Docker命令

1、docker info命令

我们安装好Docker之后,需要检查一下Docker是否安装成功了,此时我们就可以通过docker info命令来查看:

$ docker info
Client:
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 19.03.4
 Storage Driver: overlay2
  Backing Filesystem: xfs
  Supports d_type: true
  Native Overlay Diff: true
 Logging Driver: json-file
 Cgroup Driver: systemd
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: b34a5c8af56e510852c35414db4c1f4fa6172339
 runc version: 3e425f80a8c931f88e6d94a8c831b9d5aa481657
 init version: fec3683
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 3.10.0-1062.el7.x86_64
 Operating System: CentOS Linux 7 (Core)
 OSType: linux
 Architecture: x86_64
 CPUs: 1
 Total Memory: 971.8MiB
 Name: localhost.localdomain
 ID: UDIS:DXAS:7BS2:6YN4:MQ5D:NCWY:LRTN:JZTR:6T7H:FTED:HUN6:6T3X
 Docker Root Dir: /data/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  quay.io
  registry.access.redhat.com
  127.0.0.0/8
 Registry Mirrors:
  https://q2gr04ke.mirror.aliyuncs.com/
 Live Restore Enabled: true

这个命令为我们列出来一系列docker服务相关的信息,这就说明我们的Docker服务安装部署是成功的。

2、docker run 命令

当我们需要启动一个容器的时候,我们就需要用到docker run命令,此命令用于创建一个容器:

命令格式:
docker run [选项] [镜像名] [命令]

接下来,我们先从hello world开始:

$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete 
Digest: sha256:c3b4ada4687bbaa170745b3e4dd8ac3f194ca95b2d0518b417fb47e5879d9b5f
Status: Downloaded newer image for hello-world:latest

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/

我们利用一个官方镜像hello-world,启动了一个容器。当我们启动容器时,docker程序会先从本地查找相对应的镜像,如果发现本地没有,则会从官方镜像仓库去拉取对应的镜像,然后再根据镜像来启动容器。我们看到我们启动的容器,输出了一段话。稍后我们再继续介绍docker run命令相关的参数等,我们先来看下一个命令。

3、docker hub 网站

dockerhub是一个官方的镜像仓库,类似于github,网站地址是:https://hub.docker.com 这个网站提供了免费的镜像托管服务,我们可以注册一个账号来讲我们自己的镜像托管到上面。说到这里,我们就需要了解一下镜像的命名结构,一个完整的镜像,名称如下:

仓库域名/用户名/镜像名:镜像标签

Dockerhub的仓库域名是docker.io,这里的用户名就是指你在dockerhub网站上注册时的用户名,也是你的登录名,镜像名就是指具体的镜像,后面冒号后面的是该镜像的标签,这个标签可以是版本号或者备注信息等等。这里需要注意一下,因为docker是按照英文冒号去分隔镜像名和标签名的,所以,在定义标签时要避免出现冒号。

4、docker login 命令

当我们完成了在dockerhub网站的注册后,我们就可以使用docker login命令来登录dockerhub网站了,从而可以来使用这个网站为我们托管的镜像:

$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: zhy200123
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

我们可以看到,当我们使用docker login命令时,默认我们登录的就是dockerhub网站,我们输入正确的用户名和密码后就可以完成登录,提示信息还告诉我们,我们的密码通过未加密的形式存放在了/root/.docker/config.json这个文件中。我们登录成功后,就可以很方便的去使用仓库中的镜像资源了。当我们需要访问我们自己的私有仓库地址时,可以使用如下命令:

$ docker login http://私有仓库地址

5、docker images 命令

docker images这个命令可以用来查看我们本地已经存在的镜像,此命令和docker image ls命令效果一样:

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        10 months ago       1.84kB

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        10 months ago       1.84kB

在这个命令的输出结果中,我们可以看到刚才我们用过的那个hello-world镜像,输出信息中显示了此镜像的image id,这个id是镜像的唯一标识符。

6、docker search 命令

当我们想查找一下仓库中有哪些命令时,我们就可以通过此命令来实现,比如,我们现在想在仓库中查找一个名叫alpine的镜像,此时我们就可以通过这个命令来完成:

$ docker search alpine
NAME                                   DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
alpine                                 A minimal Docker image based on Alpine Linux…   5793                [OK]                
mhart/alpine-node                      Minimal Node.js built on Alpine Linux           444                                     
anapsix/alpine-java                    Oracle Java 8 (and 7) with GLIBC 2.28 over A…   428                                     [OK]
frolvlad/alpine-glibc                  Alpine Docker image with glibc (~12MB)          218                                     [OK]
gliderlabs/alpine                      Image based on Alpine Linux will help you wi…   180                                     
mvertes/alpine-mongo                   light MongoDB container                         106                                     [OK]
alpine/git                             A  simple git container running in alpine li…   100                                     [OK]
yobasystems/alpine-mariadb             MariaDB running on Alpine Linux [docker] [am…   52                                      [OK]
kiasaki/alpine-postgres                PostgreSQL docker image based on Alpine Linux   45                                      [OK]
...

7、docker pull 命令

当我们使用docker search命令查找到了我们需要的镜像后,我们就可以通过docker pull 命令把这个镜像给拉取到本地,供我们使用:

$ docker pull alpine
Using default tag: latest
latest: Pulling from library/alpine
89d9c30c1d48: Pull complete
Digest: sha256:c19173c5ada610a5989151111163d28a67368362762534d8a8121ce95cf2bd5a
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest

$ docker pull alpine:3.10.1
3.10.1: Pulling from library/alpine
050382585609: Pull complete 
Digest: sha256:6a92cd1fcdc8d8cdec60f33dda4db2cb1fcdcacf3410a8e05b3741f44a9b5998
Status: Downloaded newer image for alpine:3.10.1
docker.io/library/alpine:3.10.1

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
alpine              latest              965ea09ff2eb        2 weeks ago         5.55MB
alpine              3.10.1              b7b28af77ffe        3 months ago        5.58MB
hello-world         latest              fce289e99eb9        10 months ago       1.84kB

我们可以注意到,当我们使用docker pull命令拉取镜像时,并没有遵循上面提到的镜像的命名规则,这是因为,我们使用docker login命令成功登陆后,默认就会从docker.io/library/这个仓库中去拉取数据,所以,我们可以省略镜像名前的仓库名等。此时,我们就可以看到,我们把公共仓库中的镜像拉取到了本地,而且,当我们没有指定镜像的标签时,系统会自动帮我们拉取标签是latest的镜像,也就是最新的版本。

8、docker tag 命令

当我们把镜像拉取到本地后,我们还可以给镜像打个标签,甚至修改镜像名,此时就需要用到我们的docker tag命令了:

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
alpine              latest              965ea09ff2eb        2 weeks ago         5.55MB
alpine              3.10.1              b7b28af77ffe        3 months ago        5.58MB
hello-world         latest              fce289e99eb9        10 months ago       1.84kB

$ docker tag 965ea09ff2eb zhy200123/alpine:new
$ docker tag b7b28af77ffe zhy200123/minilinux
$ docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
zhy200123/alpine      new                 965ea09ff2eb        2 weeks ago         5.55MB
alpine                latest              965ea09ff2eb        2 weeks ago         5.55MB
alpine                3.10.1              b7b28af77ffe        3 months ago        5.58MB
zhy200123/minilinux   latest              b7b28af77ffe        3 months ago        5.58MB
hello-world           latest              fce289e99eb9        10 months ago       1.84kB

我们可以看到,利用docker tag命令可以给镜像打新的标签或者改名字,我们根据的就是镜像的image id,当我们不指定镜像的标签名时,系统就默认给这个镜像打上了lates标签,这一点是需要我们注意的。另外当我们在使用docker tag命令给镜像打标签时,镜像名前面需要加上我们的仓库用户名,此处是因为dokcer login成功了,所以省略了docker.io这个仓库域名。

9、docker ps 命令

当我们通过镜像创建了容器之后,我们需要查看当前服务器上有哪些容器,此时,我们就可以用到docker ps命令了:

$ docker ps -a 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                    PORTS               NAMES
6995094bb693        hello-world         "/hello"            24 hours ago        Exited (0) 24 hours ago                       competent_shannon

10、docker rm 命令

当一个容器运行结束了,我们从docker ps的结果中可以看到,这个容器的状态已经变成了Exited,如果这个容器不再需要了,那么我就可以通过docker rm命令来将这个容器删除掉:

$ docker ps -a 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                    PORTS               NAMES
6995094bb693        hello-world         "/hello"            24 hours ago        Exited (0) 24 hours ago                       competent_shannon

$ docker rm 6995094bb693
6995094bb693

$ docker ps -a 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

我们可以看到,我们通过容器的container id来删除掉这个容器。

11、docker rmi 命令

当我们想要删除一个不用的镜像时,那我们就可以用docker rmi命令来删除容器,删除时后面可以跟镜像的镜像ID或者镜像名,但是需要注意如下几点:

  1. 当同一个镜像拥有多个标签时,docker rmi命令只是删除了该镜像多个标签中的指定标签,并不影响镜像文件本身,但当镜像只剩下一个标签时,此时就会彻底删除镜像;
  2. docker rmi命令后面跟的是镜像ID时,会尝试删除所有指向该镜像的标签,然后删除镜像文件本身,如果该镜像存在多个标签,默认无法删除,需要加-f进行删除;
  3. 如果有基于该镜像创建的容器,且该镜像只有一个标签时,则默认无法删除镜像,需要先通过docker rm删除容器,然后再用docker rmi删除镜像,或者使用docker rmi -f强制删除(不推荐)。
$ docker ps -a 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
9f92d8e60451        hello-world         "/hello"            24 seconds ago      Exited (0) 22 seconds ago                       keen_sammet

$ docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
alpine                latest              965ea09ff2eb        2 weeks ago         5.55MB
zhy200123/alpine      new                 965ea09ff2eb        2 weeks ago         5.55MB
alpine                3.10.1              b7b28af77ffe        3 months ago        5.58MB
zhy200123/minilinux   latest              b7b28af77ffe        3 months ago        5.58MB
hello-world           latest              fce289e99eb9        10 months ago       1.84kB

$ docker rmi fce289e99eb9
Error response from daemon: conflict: unable to delete fce289e99eb9 (must be forced) - image is being used by stopped container 9f92d8e60451

从上面的命令结果可以看到,此时如果我们想删除掉这个镜像是不行的,除非加上-f选项强制删除,或者先删除容器,再删除镜像

$ docker rmi -f fce289e99eb9
Untagged: hello-world:latest
Untagged: hello-world@sha256:c3b4ada4687bbaa170745b3e4dd8ac3f194ca95b2d0518b417fb47e5879d9b5f
Deleted: sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e

$ docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
alpine                latest              965ea09ff2eb        2 weeks ago         5.55MB
zhy200123/alpine      new                 965ea09ff2eb        2 weeks ago         5.55MB
alpine                3.10.1              b7b28af77ffe        3 months ago        5.58MB
zhy200123/minilinux   latest              b7b28af77ffe        3 months ago        5.58MB

$ docker ps -a 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
9f92d8e60451        fce289e99eb9        "/hello"            3 minutes ago       Exited (0) 3 minutes ago                       keen_sammet

此时,我们可以看到,我们使用-f参数,强制删除了镜像,但是其启动的容器还在。

12、docker run命令的参数们

前面我们提到了docker run 命令,这个命令是用来创建一个容器,接下来我们来看下这个命令的常用选项有哪些:

-d, --detach               Run container in background and print container ID  将容器置入后台运行
-e, --env list             Set environment variables  为容器设置环境变量
-i, --interactive          Keep STDIN open even if not attached  保持容器标准输出,用于交互
--name string              Assign a name to the container  为容器起一个名字
-p, --publish list         Publish a container's port(s) to the host  指定容器暴露的端口号
-P, --publish-all          Publish all exposed ports to random ports  随机暴露容器的一个端口号
--rm                       Automatically remove the container when it exits  当容器退出后自动删除
-t, --tty                  Allocate a pseudo-TTY  分配tty设备,一般和-i选项搭配使用,用于交互
-u, --user string          Username or UID (format: <name|uid>[:<group|gid>])  设置容器运行的用户

13、docker exec 命令

docker exec 命令用于在运行着的容器中执行命令:

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
389c610ac450        alpine              "/bin/sh"           About an hour ago   Up About an hour                        exciting_satoshi

$ docker exec 389c610ac450 ls
bin
dev
etc
home
lib
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

$ docker exec -d 389c610ac450 ls
$ docker exec -ti 389c610ac450 ls
bin    etc    lib    mnt    proc   run    srv    tmp    var
dev    home   media  opt    root   sbin   sys    usr

我们看到,这个命令也有一些选项,分别是-d,-i,-t,其意义等同于docker run命令中对应的选项的意义。

14、docker commit 命令

docker commit命令用来制作镜像,当一个容器中的命令执行完成后,容器会退出,如果我们对容器进行了更改,这些更改也不会保存,此时我们就需要用这个命令来制作一个新的镜像。在使用这个命令时,我们一般需要使用-p选项,此时该选项会暂停容器,保证我们在commit的过程中容器不会被改变,我们还可以直接使用-t选项给新镜像打好标签。

15、docker push 命令

当我们制作好新的镜像后,我们就可以使用docker push命令来将我们的镜像推送到我们的镜像仓库中。

总结

上述我们介绍了docker常用的命令,在新版docker中,这些命令做了新的改变,例如对于容器的管理,新的版本提供的命令是 docker container [CMD],对于镜像的管理为docker image [CMD]这样的格式,这些可以让我们更明确的去管理docker相关的各类资源,所以我们更建议使用新版的docker命令来管理资源。