docker学习笔记

所有内容来自重要记录的复制,转自于https://juejin.im/book/5b7ba116e51d4556f30b476c

搭建docker环境

安装

以CentOS为例,所需命令如下,包括了启动

$ sudo yum install yum-utils device-mapper-persistent-data lvm2
$
$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
$ sudo yum install docker-ce
$
$ sudo systemctl enable docker
$ sudo systemctl start docker

查看版本

查看 Docker 版本的命令:docker version

$ sudo docker version
Client:
 Version:           18.06.1-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        e68fc7a
 Built:             Tue Aug 21 17:23:03 2018
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.1-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       e68fc7a
  Built:            Tue Aug 21 17:25:29 2018
  OS/Arch:          linux/amd64
  Experimental:     false

查看更多信息可以用docker info这个命令

配置国内镜像源

由 Docker 官方提供的国内镜像源

registry.docker-cn.com

此地址的协议是https
Linux环境下,我们可以通过修改 /etc/docker/daemon.json ( 如果文件不存在,你可以直接创建它 ) 这个 Docker 服务的配置文件达到效果。

{
    "registry-mirrors": [
        "https://registry.docker-cn.com"
    ]
}

配置后需要重启来生效

$ sudo systemctl restart docker

再通过docker info来查看,发现配置已生效

$ sudo docker info
# ......
Registry Mirrors:
 https://registry.docker-cn.com/
# ......

镜像

之所以镜像通常直接采用软件名,这还要回归到 Docker 对容器的轻量化设计中。Docker 对容器的设计和定义是微型容器而不是庞大臃肿的完整环境 ( 这当然归功于容器技术在实现虚拟化过程中性能几乎无损 ),这就使得我们通常会只在一个容器中运行一个应用程序,这样的好处自然是能够大幅降低程序之间相互的影响,也有利于利用容器技术控制每个程序所使用的资源。

搜索镜像

  1. https://hub.docker.com/中可以直接从中央仓库中搜索镜像
  2. 使用docker search tomcat命令也可以查找相应的镜像

如果不想下载最新的,而是指定镜像的tag(册子里也说了,其实就是想指定某个软件的版本进行下载),可以参考:https://www.linuxidc.com/Linux/2019-03/157690.htm

获取镜像

# 这样获取到的是最新的
sudo docker pull ubuntu

# 也可以像这样指定版本获取
sudo docker pull openresty/openresty:1.13.6.2-alpine

查看现有镜像

docker images

管理镜像

上面的docker images只能查看镜像列表,如果想查看本地某个镜像的详情,可以如下:

sudo docker inspect redis:3.2

删除镜像

sudo docker rmi ubuntu:latest

# 也可以一次删除多个镜像,中间空格
sudo docker rmi redis:3.2 redis:4.0

删除镜像的过程其实是删除镜像内的镜像层,在删除镜像命令打印的结果里,我们可以看到被删除的镜像层以及它们的 ID。当然,如果存在两个镜像共用一个镜像层的情况,你也不需要担心 Docker 会删除被共享的那部分镜像层,只有当镜像层只被当前被删除的镜像所引用时,Docker 才会将它们从硬盘空间中移除。

容器

容器的生命周期

  • Created:容器已经被创建,容器所需的相关资源已经准备就绪,但容器中的程序还未处于运行状态。
  • Running:容器正在运行,也就是容器中的应用正在运行。
  • Paused:容器已暂停,表示容器中的所有程序都处于暂停 ( 不是停止 ) 状态。
  • Stopped:容器处于停止状态,占用的资源和沙盒环境都依然存在,只是容器中的应用程序均已停止。
  • Deleted:容器已删除,相关占用的资源及存储在 Docker 中的管理信息也都已释放和移除。

创建容器

# 这种是直接创建,没有给它起名,在使用时如果指定 容器id 来使用,会很麻烦
sudo docker create nginx:1.12

# 在创建容器的时候指定下名字(给起了一个 nginx111 的名字)
# 补充一句,名字是唯一的,重复起相同的名字会报错
sudo docker create --name nginx111 nginx:1.12

注:如果本地环境中没有nginx,tag为1.12的镜像,会直接从中央仓库pull,然后再进行创建容器

启动容器

# 因为创建时指定了名字,所以启动时可以通过名称来启动
sudo docker start nginx111

下面粘贴了几张启动时的截图,可以方便启动后的状态变化

也可以用docker run命令,将docker createdocker start合并成一步,提升效率

sudo docker run --name nginx -d nginx:1.12

这里需要注意的一点是,通常来说我们启动容器会期望它运行在“后台”,而docker run在启动容器时,会采用“前台”运行这种方式,这时候我们的控制台就会衔接到容器上,不能再进行其他操作了。我们可以通过-d--detach这个选项告诉 Docker 在启动后将程序与控制台分离,使其进入“后台”运行。

管理容器

# 查看当前正在运行的容器
sudo docker ps

# 查看当前所有容器(-a <==> --all)
sudo docker ps -a

如果通过-a来启动,可以看到所有容器,status中是当前容器的运行状态
这里面有几个选项:

  • Created 此时容器已创建,但还没有被启动过。
  • Up [ Time ] 这时候容器处于正在运行状态,而这里的 Time 表示容器从开始运行到查看时的时间。
  • Exited ([ Code ]) [ Time ] 容器已经结束运行,这里的 Code 表示容器结束运行时,主程序返回的程序退出码,而 Time 则表示容器结束到查看时的时间。

停止容器

# 停止后,可以再通过docker start来启动
sudo docker stop nginx

删除容器

sudo docker rm nginx

但是容器在运行时不允许被删除,可以通过-f的选项强行删除

sudo docker rm -f nginx

进入容器

# 进入到之前创建的nginx这个容器
sudo docker exec -it nginx bash

在借助 docker exec 进入容器的时候,我们需要特别注意命令中的两个选项不可或缺,即 -i 和 -t ( 它们俩可以利用简写机制合并成 -it )。
其中 -i ( --interactive ) 表示保持我们的输入流,只有使用它才能保证控制台程序能够正确识别我们的命令。而 -t ( --tty ) 表示启用一个伪终端,形成我们与 bash 的交互,如果没有它,我们无法看到 bash 内部的执行结果。

退出容器

进入后直接按ctrl+d即可退出

为容器配置网络

目前 Docker 官方为我们提供了五种 Docker 网络驱动,分别是:Bridge Driver、Host Driver、Overlay Driver、MacLan Driver、None Driver

比较常用的就是BridgeOverlay

容器互联

在创建容器时,通过在docker createdocker run命令中,添加--link参数,指定容器名,就可以连接到相应容器上

$ sudo docker run -d --name mysql -e MYSQL_RANDOM_ROOT_PASSWORD=yes mysql
$ sudo docker run -d --name webapp --link mysql webapp:latest

这时,如果webapp应用,如果想要连接mysql数据库,如下:

String url = "jdbc:mysql://mysql:3306/webapp";

暴露端口

有点类似开防火墙功能,给防火墙开个端口号
先看下mysql默认的,默认只开放了3306和33060端口:

$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
95507bc88082        mysql:5.7           "docker-entrypoint.s…"   17 seconds ago      Up 16 seconds       3306/tcp, 33060/tcp   mysql

要开放更多的端口,可以用--expose选项:

sudo docker run -d --name mysql -e MYSQL_RANDOM_ROOT_PASSWORD=yes --expose 13306 --expose 23306 mysql:5.7

再查看下开放的端口:

$ sudo docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                       NAMES
3c4e645f21d7        mysql:5.7           "docker-entrypoint.s…"   4 seconds ago       Up 3 seconds        3306/tcp, 13306/tcp, 23306/tcp, 33060/tcp   mysql

别名连接

# --link <name>:<alias>(前面是连接的容器名,后面是给起的别名)
$ sudo docker run -d --name webapp --link mysql:database webapp:latest

这样可以通过别名来连接

String url = "jdbc:mysql://database:3306/webapp";

管理网络

如果不指定网络,默认会把创建的容器添加到一个默认的bridge的网络。而默认同一个网络内是能互相通信的,但不同网络间是不能通信的

# 可以通过docker inspect来查看网络
$ sudo docker inspect mysql
[
    {
# ......
        "NetworkSettings": {
# ......
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "bc14eb1da66b67c7d155d6c78cb5389d4ffa6c719c8be3280628b7b54617441b",
                    "EndpointID": "1e201db6858341d326be4510971b2f81f0f85ebd09b9b168e1df61bab18a6f22",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
                }
            }
# ......
        }
# ......
    }
]

创建网络

docker CLI 里与网络相关的命令都以docker network开头,其中创建网络的命令是docker network create

# 创建了一个individual的网络
$ sudo docker network create -d bridge individual

命令中通过-d来指定网络类型,而网络类型就是上面提到的那向种:bridge、host、overlay、maclan、none

查看存在的网络

$ sudo docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
bc14eb1da66b        bridge              bridge              local
35c3ef1cc27d        individual          bridge              local

加入网络

# 可以通过--network individual来指定加入到individual网络
$ sudo docker run -d --name mysql -e MYSQL_RANDOM_ROOT_PASSWORD=yes --network individual mysql:5.7

可以再来查看下mysql所加入的网络

$ sudo docker inspect mysql
[
    {
# ......
        "NetworkSettings": {
# ......
            "Networks": {
                "individual": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": [
                        "2ad678e6d110"
                    ],
                    "NetworkID": "35c3ef1cc27d24e15a2b22bdd606dc28e58f0593ead6a57da34a8ed989b1b15d",
                    "EndpointID": "41a2345b913a45c3c5aae258776fcd1be03b812403e249f96b161e50d66595ab",
                    "Gateway": "172.18.0.1",
                    "IPAddress": "172.18.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:12:00:02",
                    "DriverOpts": null
                }
            }
# ......
        }
# ......
    }
]

端口映射

就是将容器的端口映身到宿主机上,通过外网访问宿主机的端口,其实就是访问到容器的那个端口

$ sudo docker run -d --name nginx -p 80:80 -p 443:443 nginx:1.12

使用端口映射选项的格式是-p <ip>:<host-port>:<container-port>,其中 ip 是宿主操作系统的监听 ip,可以用来控制监听的网卡,默认为0.0.0.0,也就是监听所有网卡

我们可以将容器的 80 端口映射到宿主操作系统的 8080 端口,传入-p 8080:80即可
然后我们再查看下容器

$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                      NAMES
bc79fc5d42a6        nginx:1.12          "nginx -g 'daemon of…"   4 seconds ago       Up 2 seconds        0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   nginx

管理和存储数据

之前说容器使用的原则是即停即删,但容器中的数据怎么办?--册子上说一般就是挂载到宿主机的磁盘中,使得即便删除,数据也还在
挂载方式有三种:Bind MountVolumeTmpfs Mount

  • Bind Mount 能够直接将宿主操作系统中的目录和文件挂载到容器内的文件系统中,通过指定容器外的路径和容器内的路径,就可以形成挂载映射关系,在容器内外对文件的读写,都是相互可见的。
  • Volume 也是从宿主操作系统中挂载目录到容器内,只不过这个挂载的目录由 Docker 进行管理,我们只需要指定容器内的目录,不需要关心具体挂载到了宿主操作系统中的哪里。
  • Tmpfs Mount 支持挂载系统内存中的一部分到容器的文件系统里,不过由于内存和容器的特征,它的存储并不是持久的,其中的内容会随着容器的停止而消失。

挂载到容器

使用-v--volume命令
-v <host-path>:<container-path> ,其中 host-path 和 container-path 分别代表宿主操作系统中的目录和容器中的目录。这里的路径要用绝对路径,特别是<host-path>,如果仅仅是个名称的话,就不是Bind Mount,而是Volume方式

$ sudo docker run -d --name nginx -v /webapp/html:/usr/share/nginx/html nginx:1.12

可以查看下容器

$ sudo docker inspect nginx
[
    {
# ......
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/webapp/html",
                "Destination": "/usr/share/nginx/html",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
# ......
    }
]

可以看到这里的RW = true,也就是容器内的数据可以写文件到宿主机,如果只让容器只读,可以加:ro参数

$ sudo docker run -d --name nginx -v /webapp/html:/usr/share/nginx/html:ro nginx:1.12

挂载临时文件目录

由于Tmpfs Mount这种方式是挂载到宿主机的内存中,所以不需要指定宿主机目录,直接指定要挂载的容器目录就可以了

$ sudo docker run -d --name webapp --tmpfs /webapp/cache webapp:latest

这时再查看下详情

$ sudo docker inspect webapp
[
    {
# ......
         "Tmpfs": {
            "/webapp/cache": ""
        },
# ......
    }
]

使用数据卷

其实也就是用 Volume方式挂载。因为是由Docker管理,不用去管他给挂载到宿主机的位置,但可以通过操作数据卷的方式来操作它。

# 也是使用-v来挂载,只是直接指定容器的目录即可
$ sudo docker run -d --name webapp -v /webapp/storage webapp:latest

使用docker inspect查看,其实就是挂载到了/var/lib/docker/volumes/目录下。

$ sudo docker inspect webapp
[
    {
# ......
        "Mounts": [
            {
                "Type": "volume",
                "Name": "2bbd2719b81fbe030e6f446243386d763ef25879ec82bb60c9be7ef7f3a25336",
                "Source": "/var/lib/docker/volumes/2bbd2719b81fbe030e6f446243386d763ef25879ec82bb60c9be7ef7f3a25336/_data",
                "Destination": "/webapp/storage",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
# ......
    }
]

但是上面没有为数据卷命名,所以我们挂载时,可以手动起一个数据卷名,规则:-v :。如果该数据卷已存在,直接引用;没有才去创建它

# 手动叫appdata的数据卷名
$ sudo docker run -d --name webapp -v appdata:/webapp/storage webapp:latest

共用数据卷

可以给多个容器挂载到同一数据卷上(起一样的名),这样数据也就共享了

$ sudo docker run -d --name webapp -v html:/webapp/html webapp:latest
$ sudo docker run -d --name nginx -v html:/usr/share/nginx/html:ro nginx:1.12

数据卷管理

可以直接通过docker volume xxx来操作数据卷

创建数据卷

$ sudo docker volume create appdata

查看数据卷

使用docker volume ls来查看

$ sudo docker volume ls
DRIVER              VOLUME NAME
local               html
local               appdata

删除数据卷

可以使用docker volume rm来删除指定数据卷

$ sudo docker volume rm appdata

在删除数据卷之前,我们必须保证数据卷没有被任何容器所使用 ( 也就是之前引用过这个数据卷的容器都已经删除 ),否则 Docker 不会允许我们删除这个数据卷。

有些数据卷在创建时没有指定名称
这时删除可以用下面两种方式:
1.在删除容器时连带着删除它,使用-v命令即可

$ sudo docker rm -v webapp

2.使用docker volume prune,它可以删除那些没有被容器引用的数据卷

$ sudo docker volume prune -f
Deleted Volumes:
af6459286b5ce42bb5f205d0d323ac11ce8b8d9df4c65909ddc2feea7c3d1d53
0783665df434533f6b53afe3d9decfa791929570913c7aff10f302c17ed1a389
65b822e27d0be93d149304afb1515f8111344da9ea18adc3b3a34bddd2b243c7
# ......
posted @ 2020-01-17 09:22  半湖思絮  阅读(291)  评论(0编辑  收藏  举报