docker基础入门

docker基础入门Docker简介什么是虚拟机?通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。在计算机中创建虚拟机时,需要将实体机的部分硬盘和内存容量作为虚拟机的硬盘和内存容量。什么是容器?容器技术是和我们的宿主机共享硬件资源及操作系统,可以实现资源的动态分配。容器包含应用和

大家好,欢迎来到IT知识分享网。

Docker简介

什么是虚拟机?

通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。在计算机中创建虚拟机时,需要将实体机的部分硬盘和内存容量作为虚拟机的硬盘和内存容量。

什么是容器?

容器技术是和我们的宿主机共享硬件资源及操作系统,可以实现资源的动态分配。容器包含应用和其所有的依赖包,但是与其他容器共享内核。容器在宿主机操作系统中,在用户空间以分离的进程运行。

image-20230217150412661

二者对比

docker基础入门

Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。

Docker架构

docker基础入门

Docker有三个组件和三个基本元素。三个组件:

  • Docker Client 是用户界面,它支持用户与Docker Daemon之间通信。
  • Docker Daemon运行于主机上,处理服务请求。
  • Docker Index是中央registry,支持拥有公有与私有访问权限的Docker容器镜像的备份。

三个基本要素分别是:

  • Docker Containers负责应用程序的运行,包括操作系统、用户添加的文件以及元数据。
  • Docker Images是一个只读模板,用来运行Docker容器。
  • DockerFile是文件指令集,用来说明如何自动创建Docker镜像

我们常常与之打交道的是:镜像(Image)、容器(Container)和仓库(Repository)

安装docker

官方文档:https://docs.docker.com/engine/install/

  1. 卸载本机自带docker
yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
  1. 安装依赖
yum install -y yum-utils
  1. 设置docker镜像仓库 (这里用的是阿里的,也可以用官方的yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo)
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

设置后需要更新下yum索引

yum makecache fast
  1. 安装docker
yum install docker-ce docker-ce-cli containerd.io
  1. 配置docker镜像加速
  • 访问阿里云 https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors 镜像工具-镜像加速器
  • 根据操作文档配置即可,以centos为例:
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://vxxxxxaa.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

当yum配置的是官当的地址时,安装出现报错,参考https://stackoverflow.com/questions/65878769/cannot-install-docker-in-a-rhel-server处理

  1. 查看docker版本

    [root@localhost ~]# docker version
    Client: Docker Engine - Community
     Version:           20.10.5
     API version:       1.41
     Go version:        go1.13.15
     Git commit:        55c4c88
     Built:             Tue Mar  2 20:33:55 2021
     OS/Arch:           linux/amd64
     Context:           default
     Experimental:      true
    
    Server: Docker Engine - Community
     Engine:
      Version:          20.10.5
      API version:      1.41 (minimum version 1.12)
      Go version:       go1.13.15
      Git commit:       363e9a8
      Built:            Tue Mar  2 20:32:17 2021
      OS/Arch:          linux/amd64
      Experimental:     false
     containerd:
      Version:          1.4.4
      GitCommit:        05f951a3781f4f2c1911b05e61c160e9c30eaa8e
     runc:
      Version:          1.0.0-rc93
      GitCommit:        12644e614e25b05da6fd08a38ffa0cfe1903fdec
     docker-init:
      Version:          0.19.0
      GitCommit:        de40ad0
    [root@localhost ~]# 
    
    
    
    
  2. Docker卸载

sudo yum remove docker-ce docker-ce-cli containerd.io
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd

Docker常用命令

先看几张网络流传的对于docker命令的介绍图解。

docker基础入门

docker基础入门

可以看到常用命令主要围绕着镜像、容器、仓库和Dockerfile这四个对象,下面我们逐一看一下相关的命令。

帮助命令

docker version	# 查看docker版本
docker info			# 显示docker系统信息,包括镜像和容器的数量
docker 命令 --help	# 命令的帮助文档

镜像命令

docker images

[root@localhost ~]# docker images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

# 名词解释
REPOSITORY  # 镜像仓库源
TAG 	# 镜像标签
IMAGE ID  # 镜像id
CREATED  # 镜像创建时间
SIZE  # 镜像大小


Options:
  -a, --all   # 显示所有镜像
  -q, --quiet  # 只显示镜像的ID
  -f, --filter  # 显示符合过滤条件的镜像,例如 --filter=STARS=5000 显示STARTS数量大于5000的镜像

docker search image 镜像搜索

[root@localhost ~]# docker search nginx --filter=STARS=1000
NAME                  DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
nginx                 Official build of Nginx.                        14692     [OK]       
jwilder/nginx-proxy   Automated Nginx reverse proxy for docker con…   2006                 [OK]
[root@localhost ~]#

docker pull image 镜像下载

# docker pull 镜像[:tag]  不跟tag默认下载最新镜像latest
[root@localhost ~]# 
[root@localhost ~]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
75646c2fb410: Pull complete 
6128033c842f: Pull complete 
71a81b5270eb: Pull complete 
b5fc821c48a1: Pull complete 
da3f514a6428: Pull complete 
3be359fed358: Pull complete 
Digest: sha256:1fefbe787475516735b828516f593412addcc9ad7a8e5b791647e58f094731d2
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
[root@localhost ~]# 

docker rmi 镜像ID

docker rmi `docker images -aq` # 删除所有镜像
docker rmi 镜像id  # 删除指定镜像
docker rmi 镜像id 镜像id  # 删除指定镜像

镜像离线备份/恢复

docker save -o file.tar imageID  # 保存镜像
docker load -i file.tar   # 解压镜像

容器命令

有了镜像才能够创建容器,容器是镜像的一个运行实体。基于镜像的只读层,新建一个读写层,所有对容器进行的操作都会被写入到读写层。

容器运行

docker run [可选参数] image

# 参数说明
--name='NAME' 容器名字,nginx1 nginx2 来进行区分
-d 后台的方式启动
-t 以terminal终端的方式运行
-i 以input交互的模式启动镜像并运行
-p 指定端口运行
	-p ip:主机端口:容器端口  对于多网卡的主机,可以指定使用哪块网卡的端口
	-p 主机端口:容器端口  是指容器内的端口映射到主机的端口对外提供服务
-P 随机指定端口
--rm 启动后直接删除

> 以交互模式运行centos,启动并进入容器
[root@localhost ~]# docker run -it --name c1 centos bash
[root@137d0777f309 /]# 
[root@137d0777f309 /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
# exit退出容器,导致容器直接退出
[root@137d0777f309 /]# exit
exit
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
# 查看所有容器
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED          STATUS                     PORTS     NAMES
137d0777f309   centos    "bash"    14 seconds ago   Exited (0) 3 seconds ago             c1
[root@localhost ~]# 
# 进入容器会报错,因为容器并未运行
[root@localhost ~]# docker exec -it 137d0777f309 sh
Error response from daemon: Container 137d0777f309a7931d837076af37a37d605209cec655fcf3b97d96f3d2171874 is not running
[root@localhost ~]# 
# 通过start运行起来这个容器
[root@localhost ~]# docker start 137d0777f309
137d0777f309
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED         STATUS         PORTS     NAMES
137d0777f309   centos    "bash"    3 minutes ago   Up 4 seconds             c1
[root@localhost ~]# 
[root@localhost ~]# docker run -it --name c2 centos bash
[root@ecbb054ff06a /]# 
# 进入容器后,使用Ctrl + p + q 退出容器而不退出
[root@ecbb054ff06a /]# [root@localhost ~]# 
[root@localhost ~]# 
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED          STATUS          PORTS     NAMES
ecbb054ff06a   centos    "bash"    11 seconds ago   Up 11 seconds             c2
137d0777f309   centos    "bash"    5 minutes ago    Up 2 minutes              c1
[root@localhost ~]# 
[root@localhost ~]#

查看所有容器

# docker ps [参数]

# 参数说明
-a 列出所有容器(含已停止的)
-n=? 显示最近创建的几个容器
-q 只显示容器的id

退出容器

exit  # 直接退出容器并推出
Ctrl + p + q  # 不停止容器退出

删除容器

# docker container rm [可选参数]

# 可选参数
Options:
  -f, --force     强制删除
  -l, --link      Remove the specified link
  -v, --volumes   删除容器和数据卷

启动和停止容器

docker star 容器id		# 启动容器
docker restart 容器id		# 重启容器
docker stop 容器id		# 停止当前正在运行的容器
docker kill 容器id		# 强制停止当前容器

容器启动常见新手坑

docker容器运行必须要有一个前台进程,docker服务发现如果一个容器未启动一个应用(未对外提供服务),就会直接结束这个容器。

# 下面演示一下后台运行 -d
# centos直接启动了但是未对外部提供服务 
[root@localhost ~]# docker run --name c1 -d centos
643bfdc352fb5b058c6a59189d9cfa94ca4d9290895e9ad63d1309a858780cec
[root@localhost ~]# 
# nginx启动是会对外提供服务的
[root@localhost ~]# docker run --name n1 -d nginx
c1facbaa3e30e8db44cc966f2b53ce194cbecb39b41e99e0572b0ec764ae6195
[root@localhost ~]# 
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
c1facbaa3e30   nginx     "/docker-entrypoint.…"   3 seconds ago   Up 2 seconds   80/tcp    n1
[root@localhost ~]# 
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                      PORTS     NAMES
c1facbaa3e30   nginx     "/docker-entrypoint.…"   6 seconds ago    Up 5 seconds                80/tcp    n1
643bfdc352fb   centos    "/bin/bash"              12 seconds ago   Exited (0) 11 seconds ago             c1
[root@localhost ~]# 

常用其他命令

日志查看

# docker logs [可选参数] 容器id

# 可选参数:
  -f, --follow         实时刷新日志
      --since string   某时刻后 (例. 2013-01-02T13:23:37Z) 或时间段内 (例. 42m for 42 minutes)
  -n, --tail string    尾部行数
  -t, --timestamps     Show timestamps
      --until string   某时刻之前 (例. 2013-01-02T13:23:37Z) or 或时间段前 (e.g. 42m for 42 minutes)


# 日志查看
[root@localhost ~]# 
[root@localhost ~]# docker ps 
CONTAINER ID   IMAGE     COMMAND                  CREATED        STATUS        PORTS     NAMES
c1facbaa3e30   nginx     "/docker-entrypoint.…"   10 hours ago   Up 10 hours   80/tcp    n1
[root@localhost ~]# 
[root@localhost ~]# docker logs -tf --tail 30 c1facbaa3e30
2021-04-10T03:13:52.168667753Z /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
2021-04-10T03:13:52.168748946Z /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
2021-04-10T03:13:52.176780131Z /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
2021-04-10T03:13:52.196616259Z 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
2021-04-10T03:13:52.201315025Z 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
2021-04-10T03:13:52.209915964Z /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
2021-04-10T03:13:52.214189363Z /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
2021-04-10T03:13:52.225238822Z /docker-entrypoint.sh: Configuration complete; ready for start up

^C
[root@localhost ~]# 

查看容器内的进程信息

# docker ps 容器id
[root@localhost ~]# 
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED        STATUS        PORTS     NAMES
c1facbaa3e30   nginx     "/docker-entrypoint.…"   10 hours ago   Up 10 hours   80/tcp    n1
[root@localhost ~]# 
[root@localhost ~]# 
[root@localhost ~]# docker top c1facbaa3e30
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                9072                9053                0                   11:13               ?                   00:00:00            nginx: master process nginx -g daemon off;
101                 9130                9072                0                   11:13               ?                   00:00:00            nginx: worker process
[root@localhost ~]# 

查看容器资源使用

# docker stats [容器ID]
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS

# 名词解释
CONTAINER  # 容器ID
NAME 	# 容器名称
CPU  # CPU使用
MEM  # 内存已用/最大/占比
NET  # 网络吞吐
BLOCK	# 磁盘读写
PIDS	# 进程数

查看容器的元数据

# docker inspect 容器id
[root@localhost ~]# 
[root@localhost ~]# docker inspect c1facbaa3e30
[
    {
        "Id": "c1facbaa3e30e8db44cc966f2b53ce194cbecb39b41e99e0572b0ec764ae6195",
        "Created": "2021-04-10T03:13:51.657700582Z",
        "Path": "/docker-entrypoint.sh",
        "Args": [
            "nginx",
            "-g",
            "daemon off;"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 9072,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2021-04-10T03:13:52.163838429Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:7ce4f91ef623b9672ec12302c4a710629cd542617c1ebc616a48d06e2a84656a",
        "ResolvConfPath": "/var/lib/docker/containers/c1facbaa3e30e8db44cc966f2b53ce194cbecb39b41e99e0572b0ec764ae6195/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/c1facbaa3e30e8db44cc966f2b53ce194cbecb39b41e99e0572b0ec764ae6195/hostname",
        "HostsPath": "/var/lib/docker/containers/c1facbaa3e30e8db44cc966f2b53ce194cbecb39b41e99e0572b0ec764ae6195/hosts",
        "LogPath": "/var/lib/docker/containers/c1facbaa3e30e8db44cc966f2b53ce194cbecb39b41e99e0572b0ec764ae6195/c1facbaa3e30e8db44cc966f2b53ce194cbecb39b41e99e0572b0ec764ae6195-json.log",
        "Name": "/n1",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "CgroupnsMode": "host",
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "KernelMemory": 0,
            "KernelMemoryTCP": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/e9ce2080590ff9df7aca2fe013e3f3f7c28bcfdc065c67b6f85cc3fb8a4a0bd3-init/diff:/var/lib/docker/overlay2/03ba41cbb98e51ac77550ebdaa45842f6ecbf8cfa5e46bbc11bcf69a65daffca/diff:/var/lib/docker/overlay2/0a33c5f1b1453c300ed2812ec8cad78e17bdce0b90e1cea3763e7ec7b34f6e1c/diff:/var/lib/docker/overlay2/0dc81292ba503f9ad3bbed6d8e1e0b7e71094f4fda08fcdab5f9d1ab465a3cd5/diff:/var/lib/docker/overlay2/f746f88696bc2be718cddbf9be61715eaef1afb412274f7e5525324ed208f220/diff:/var/lib/docker/overlay2/52d5cdf8a796baa2cc9a5cd5c539aa8c0cd3d3f8f9cf6372af1b5acc0c3a4a1f/diff:/var/lib/docker/overlay2/4bacbf47f498390759c41b25f9a0628383696e358b93c93650e3a47de00c002c/diff",
                "MergedDir": "/var/lib/docker/overlay2/e9ce2080590ff9df7aca2fe013e3f3f7c28bcfdc065c67b6f85cc3fb8a4a0bd3/merged",
                "UpperDir": "/var/lib/docker/overlay2/e9ce2080590ff9df7aca2fe013e3f3f7c28bcfdc065c67b6f85cc3fb8a4a0bd3/diff",
                "WorkDir": "/var/lib/docker/overlay2/e9ce2080590ff9df7aca2fe013e3f3f7c28bcfdc065c67b6f85cc3fb8a4a0bd3/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "c1facbaa3e30",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.19.9",
                "NJS_VERSION=0.5.3",
                "PKG_RELEASE=1~buster"
            ],
            "Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],
            "Image": "nginx",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
            },
            "StopSignal": "SIGQUIT"
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "215b083c80cd6163a5cecab41a0c9687d13ff1a1478fe3279687a49f52d09c25",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "80/tcp": null
            },
            "SandboxKey": "/var/run/docker/netns/215b083c80cd",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "0c087f336faab04c2700f88a4f0cf82e6e36155f468d4cd023d3431c6b15c075",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "ecfc352b4b0dada9e5b6ed430866782912063791dab093f328c1857341afdbdd",
                    "EndpointID": "0c087f336faab04c2700f88a4f0cf82e6e36155f468d4cd023d3431c6b15c075",
                    "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
                }
            }
        }
    }
]
[root@localhost ~]# 

进入当前正在运行的容器

# 方式一:docker exec -it 容器id 命令

[root@172 ~]# 
[root@172 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES
074cede752ab        d0bd3a0d13e7        "/start.sh"         5 hours ago         Up 5 hours          0.0.0.0:8000->80/tcp   batch_log
[root@172 ~]# 
# 一般使用 bash 或 /bin/bash
[root@172 ~]# 
[root@172 ~]# docker exec -it batch_log bash
root@074cede752ab:/app# pwd
/app
root@074cede752ab:/app# 

# 方式二:docker attach 容器id
[root@172 ~]# docker attach batch_log
[2021-06-21 15:08:25 +0800] [1] [INFO] Handling signal: winch
[2021-06-21 15:08:25 +0800] [1] [INFO] Handling signal: winch

# 比较
docker exec			# 打开容器内的新的终端
docker attach		# 进入容器正在执行的终端

容器内外文件复制

# docker cp 主机文件路径 容器id:路径
# docker cp 容器id:路径 主机路径

[root@localhost ~]# 
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED        STATUS         PORTS     NAMES
c1facbaa3e30   nginx     "/docker-entrypoint.…"   10 hours ago   Up 2 seconds   80/tcp    n1
[root@localhost ~]# 
[root@localhost ~]# ls
1000  anaconda-ks.cfg  initial-setup-ks.cfg
[root@localhost ~]# touch abc.txt
[root@localhost ~]# 
[root@localhost ~]# docker exec -it c1facbaa3e30 bash
root@c1facbaa3e30:/# ls
bin  boot  dev	docker-entrypoint.d  docker-entrypoint.sh  etc	home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@c1facbaa3e30:/# pwd
/
root@c1facbaa3e30:/# 
root@c1facbaa3e30:/# touch sss.txt
root@c1facbaa3e30:/# exit
exit
[root@localhost ~]# docker cp abc.txt c1facbaa3e30:/
[root@localhost ~]# docker cp c1facbaa3e30:/sss.txt .
[root@localhost ~]# ls
1000  abc.txt  anaconda-ks.cfg  initial-setup-ks.cfg  sss.txt
[root@localhost ~]# 
[root@localhost ~]# docker exec -it c1facbaa3e30 bash
root@c1facbaa3e30:/# ls
abc.txt  bin  boot  dev  docker-entrypoint.d  docker-entrypoint.sh  etc  home  lib  lib64  media  mnt  opt  proc  root	run  sbin  srv	sss.txt  sys  tmp  usr	var
root@c1facbaa3e30:/# 
root@c1facbaa3e30:/# 

查看容器的资源使用

# docker stats 列出所有容器的使用状态

[root@localhost ~]# 
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS              PORTS                    NAMES
b4e5f1c68098   tomcat    "catalina.sh run"        11 minutes ago   Up 11 minutes       0.0.0.0:8888->8080/tcp   t2
675d785b758f   tomcat    "catalina.sh run"        18 hours ago     Up About a minute   8080/tcp                 t1
c1facbaa3e30   nginx     "/docker-entrypoint.…"   28 hours ago     Up About a minute   80/tcp                   n1
[root@localhost ~]# 
[root@localhost ~]# 
[root@localhost ~]# docker stats

CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O          BLOCK I/O     PIDS
b4e5f1c68098   t2        0.32%     125.7MiB / 1.795GiB   6.84%     10.8kB / 127kB   62.9MB / 0B   30
675d785b758f   t1        0.11%     67.73MiB / 1.795GiB   3.69%     656B / 0B        8.09MB / 0B   29
c1facbaa3e30   n1        0.00%     2.633MiB / 1.795GiB   0.14%     656B / 0B        22.4MB / 0B   2


数据卷

​ Docker的镜像是由一系列的只读层组合而来,当启动一个容器的时候,Docker加载镜像的所有只读层,并在最上层加入一个读写层。这个设计使得Docker可以提高镜像构建、存储和分发的效率,节省了时间和存储空间,然而也存在如下问题。

(1)容器中的文件在宿主机上存在形式复杂,不能在宿主机上很方便的对容器中的文件进行访问

(2)多个容器之间的数据无法共享

(3)当删除容器时,容器产生的数据将丢失

​ 为了解决这些问题,Docker引入了数据卷(volume)机制。volume是存在一个或多个容器中的特定文件或文件夹,这个目录能够独立于联合文件系统的形式在宿主机中存在,并为数据的共享与持久提供一下便利

​ (1)volume在容器创建时就初始化,在容器运行时就可以使用其中的文件

​ (2)volume能在不同的容器之间共享和重用

​ (3)对volume中的数据的操作会马上生效

​ (4)对volume中数据操作不会影响到镜像本身

​ (5)volume的生存周期独立于容器的生存周期,即使删除容器,volume仍然会存在,没有任何容器使用的volume也不会被Docker删除

数据卷使用

# 数据卷挂载
# docker run -v 数据卷:容器卷

匿名挂载

只指定容器中的挂载点,便于容器内部文件访问(一般不用)

docker run -itd -v /data/app 镜像ID
# docker volume COMMAND

# 可选参数:
  create      # 创建数据卷
  inspect     # 查看数据卷详情
  ls          # 列出所有数据卷
  prune       # 删除搜有未被使用的数据卷
  rm          # 删除一个或多个数据卷

[root@localhost ~]# docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED             STATUS             PORTS                    NAMES
2ce37b1523e9   nginx                 "/docker-entrypoint.…"   3 minutes ago       Up 3 minutes       0.0.0.0:83->80/tcp       n3
854524b99b60   nginx                 "/docker-entrypoint.…"   4 minutes ago       Up 4 minutes       0.0.0.0:82->80/tcp       n2
e1ad3a34b432   portainer/portainer   "/portainer"             About an hour ago   Up About an hour   0.0.0.0:9000->9000/tcp   portainer
b4e5f1c68098   tomcat                "catalina.sh run"        About an hour ago   Up About an hour   0.0.0.0:8888->8080/tcp   t2
675d785b758f   tomcat                "catalina.sh run"        19 hours ago        Up About an hour   8080/tcp                 t1
c1facbaa3e30   nginx                 "/docker-entrypoint.…"   30 hours ago        Up About an hour   80/tcp                   n1
[root@localhost ~]# 
[root@localhost ~]# docker volume ls
DRIVER    VOLUME NAME
local     a4bc07fe3366356230d5467998ddf2a243b660e0b3b765f64efc5e3dee11c3be
local     nginx3
[root@localhost ~]# 
[root@localhost ~]# 

# 查看数据卷详情  docker volume inspect 具名
[root@localhost ~]# docker volume inspect nginx3
[
    {
        "CreatedAt": "2021-04-11T16:40:52+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/nginx3/_data",
        "Name": "nginx3",
        "Options": null,
        "Scope": "local"
    }
]
[root@localhost ~]#


-v 容器目录				# 匿名挂载,指定容器内部的挂载点。例如, -v /data/work
-v 卷名:容器目录			# 具名挂载,指定具名。例如, -v App:/app 直接声明了具名,一般默认主机的挂在路径为 `/data/docker/volumes/具名`
-v 卷名:容器目录:ro		# 具名挂载,只读(rw读写),只能在主机操作,无法在容器内操作
-v /主机目录:容器目录		# 指定目录挂载

具名挂载

主机挂载

说明:

  1. 匿名挂载是为了确定容器的挂载点的位置,方便操作容器内部的文件
  2. 具名挂在是给对应的挂载起了一个名称,便于在主机查找被挂载点,可以使用 docker volumes ls 方便的查看到匿名和具名挂载信息,同时,具名挂载一般主机目录是在
  3. 主机文件挂载

数据卷共享

[root@localhost test_docker]# docker run -it --name c1 -v c1_volume bf536fcd39c8
[root@b262d2b6c690 /]# 
[root@localhost test_docker]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS     NAMES
b262d2b6c690   bf536fcd39c8   "/bin/sh -c /bin/bash"   26 seconds ago   Up 25 seconds             c1
[root@localhost test_docker]#
[root@localhost test_docker]# docker inspect b262d2b6c690

docker基础入门

# 启动一个容器挂载继承自上述c1
[root@localhost test_docker]# docker run -it --name c2 --volumes-from c1 bf536fcd39c8

[root@localhost test_docker]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS         PORTS     NAMES
c7ce81b0acd1   bf536fcd39c8   "/bin/sh -c /bin/bash"   10 seconds ago   Up 9 seconds             c2
b262d2b6c690   bf536fcd39c8   "/bin/sh -c /bin/bash"   3 minutes ago    Up 3 minutes             c1
[root@localhost test_docker]# 
# 查看挂载信息
[root@localhost test_docker]# docker inspect c2

docker基础入门

DockerFile

DockerFile实践

[root@it st_dockerfile1]# ll
总用量 249656
-rw-r--r-- 1 root  root       1092 4月  15 16:01 application.properties
-rw-r--r-- 1 root  root       2760 4月  15 16:01 application-test.properties
-rw-r--r-- 1 root  root  104349690 4月  15 15:58 automated-testing-1.0.3-SNAPSHOT.jar
-rw-r--r-- 1 root  root    7558560 4月  15 15:58 dist1.0.3.zip
-rw-r--r-- 1 root  root        351 4月  16 17:29 dockerfile
drwxr-xr-x 8 10143 10143       273 12月  9 20:50 jdk1.8.0_281
-rw-r--r-- 1 root  root  143722924 4月  16 13:49 jdk-8u281-linux-x64.tar.gz
[root@it st_dockerfile1]# 
[root@it st_dockerfile1]# cat dockerfile 
# 继承于哪个基础镜像
FROM centos
# 设置环境变量,用于下方引用
ENV work_dir /home/works
# 设置工作路径,一般在文件操作前指定工作路径(类似于cd)
WORKDIR $work_dir
# 吧当前主机下的文件拷贝到工作路径下
COPY jdk1.8.0_281 ./jdk1.8.0_281
# 设置环境变量
ENV JAVA_HOME $work_dir/jdk1.8.0_281
ENV CLASSPATH $JAVA_HOME/lib/
ENV PATH $PATH:$JAVA_HOME/bin
# 拷贝相关配置文件
COPY application.properties .
COPY application-test.properties .
COPY automated-testing-1.0.3-SNAPSHOT.jar .
# 执行命令
CMD java -jar automated-testing-1.0.3-SNAPSHOT.jar
[root@it st_dockerfile1]# 

说明:

  1. 只有ENV 中配置的变量才能在接下来的命令中引用(直接引用$WORKDIR是不行的)
  2. jdk一定要搞清楚是32位还是64位
  3. COPY 路径尽量用绝对路径,不要用相对

打包镜像

# docker build [OPTIONS] PATH | URL | -


# 可选参数:
      --add-host list           Add a custom host-to-IP mapping (host:ip)
      --build-arg list          Set build-time variables
      --cache-from strings      Images to consider as cache sources
      --cgroup-parent string    Optional parent cgroup for the container
      --compress                Compress the build context using gzip
      --cpu-period int          Limit the CPU CFS (Completely Fair Scheduler) period
      --cpu-quota int           Limit the CPU CFS (Completely Fair Scheduler) quota
  -c, --cpu-shares int          CPU shares (relative weight)
      --cpuset-cpus string      CPUs in which to allow execution (0-3, 0,1)
      --cpuset-mems string      MEMs in which to allow execution (0-3, 0,1)
      --disable-content-trust   Skip image verification (default true)
  -f, --file string             Name of the Dockerfile (Default is 'PATH/Dockerfile')
      --force-rm                Always remove intermediate containers
      --iidfile string          Write the image ID to the file
      --isolation string        Container isolation technology
      --label list              Set metadata for an image
  -m, --memory bytes            Memory limit
      --memory-swap bytes       Swap limit equal to memory plus swap: '-1' to enable unlimited swap
      --network string          Set the networking mode for the RUN instructions during build (default "default")
      --no-cache                Do not use cache when building the image
      --pull                    Always attempt to pull a newer version of the image
  -q, --quiet                   Suppress the build output and print image ID on success
      --rm                      Remove intermediate containers after a successful build (default true)
      --security-opt strings    Security options
      --shm-size bytes          Size of /dev/shm
  -t, --tag list                Name and optionally a tag in the 'name:tag' format
      --target string           Set the target build stage to build.
      --ulimit ulimit           Ulimit options (default [])
[root@localhost test_docker]# 

使用上方dockerfile实践

# 使用dockerfile打包

[root@localhost test_docker]# docker build -f dockerfile -t mycentos:1.0.1 .
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM centos
 ---> 300e315adb2f
Step 2/4 : VOLUME ['volum1','data2']
 ---> Running in d652b383eac9
Removing intermediate container d652b383eac9
 ---> 8ec94a35e0bb
Step 3/4 : CMD echo '------end--------'
 ---> Running in 4ba29a74a0c0
Removing intermediate container 4ba29a74a0c0
 ---> 9ff8a0181629
Step 4/4 : CMD /bin/bash
 ---> Running in 91e6fccc2b2c
Removing intermediate container 91e6fccc2b2c
 ---> 1e4167a4374b
Successfully built 1e4167a4374b
Successfully tagged mycentos:1.0.1
[root@localhost test_docker]#

# 查看打包的镜像

[root@localhost test_docker]# 
[root@localhost test_docker]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED             SIZE
mycentos              1.0.1     1e4167a4374b   6 minutes ago       209MB
t2                    1.0.1     bc3e82a80c49   About an hour ago   672MB
tomcat                latest    b72e45a11ad9   4 days ago          667MB
nginx                 latest    7ce4f91ef623   11 days ago         133MB
mysql                 5.7       cd0f0b1e283d   11 days ago         449MB
portainer/portainer   latest    580c0e4e98b0   3 weeks ago         79.1MB
centos                latest    300e315adb2f   4 months ago        209MB
[root@localhost test_docker]# 

DockerFile中的数据卷

# 通过dockerfile创建镜像,并添加volume

[root@localhost test_docker]# pwd
/home/test_docker
[root@localhost test_docker]# cat dockerfile 
FROM centos
VOLUME ['volum1','data2']
CMD echo '------end--------'
CMD /bin/bash
[root@localhost test_docker]#

# FROM centos						指定基础镜像
# VOLUME ['volum1','data2']			创建数据卷,此处如果使用单引号则只创建一个匿名卷,如果是双引号,则创建两个匿名卷,见下方图
# CMD echo '------end--------'		执行命令
# CMD /bin/bash						执行命令

双引号是两个卷

docker基础入门

docker基础入门

单引号是一个卷,被解析成描述字段

docker基础入门

docker基础入门

CMD和ENTRYPOINT的区别

CMD				# 指定容器启动后执行的命令(只有最后一条cmd会生效),命令可被替代
ENTRYPOINT		# 指定容器启动后执行的命令(只有最后一条cmd会生效),不会被替代,可被追加命令或参数

使用CMD

  1. 只执行最后一条
[root@it lwj]# cat Dockerfile 
FROM centos
MAINTAINER wjlv4@iflytek.com

CMD ["pwd"]
CMD ["ls"]
#  打包镜像
[root@it lwj]# docker build -t t1:1.0 .
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM centos
 ---> 300e315adb2f
Step 2/4 : MAINTAINER wjlv4@iflytek.com
 ---> Running in 5343d5f910e2
Removing intermediate container 5343d5f910e2
 ---> 417eee370d63
Step 3/4 : CMD ["pwd"]
 ---> Running in 7bac8649856c
Removing intermediate container 7bac8649856c
 ---> 1db347fe84b4
Step 4/4 : CMD ["ls"]
 ---> Running in c333a126697f
Removing intermediate container c333a126697f
 ---> c565ada161ff
Successfully built c565ada161ff
Successfully tagged t1:1.0
# 执行
[root@it lwj]# docker run c56
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
[root@it lwj]# 

  1. 命令会被覆盖

当输入pwd或者w时原始的命令被覆盖了

[root@it lwj]# 
[root@it lwj]# docker run c56 pwd
/
[root@it lwj]# 
[root@it lwj]# docker run c56 w
 04:57:17 up 104 days, 24 min,  0 users,  load average: 0.00, 0.01, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
[root@it lwj]# 

使用ENTRYPOINT

[root@it lwj]# cat Dockerfile 
FROM centos
MAINTAINER wjlv4@iflytek.com

ENTRYPOINT ["w"]
ENTRYPOINT ["ls"]
# 镜像打包
[root@it lwj]# docker build -t t2:1.0 .
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM centos
 ---> 300e315adb2f
Step 2/4 : MAINTAINER wjlv4@iflytek.com
 ---> Running in 5278eed96b9f
Removing intermediate container 5278eed96b9f
 ---> cf401a10d8d8
Step 3/4 : ENTRYPOINT ["w"]
 ---> Running in c7c4b639e4e9
Removing intermediate container c7c4b639e4e9
 ---> 36b175abe2a1
Step 4/4 : ENTRYPOINT ["ls"]
 ---> Running in 97f320379f8b
Removing intermediate container 97f320379f8b
 ---> f7ec1769e374
Successfully built f7ec1769e374
Successfully tagged t2:1.0
[root@it lwj]#
  1. 仅执行最后一条
[root@it lwj]# docker run f7
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
[root@it lwj]# 
  1. 命令不会被覆盖
[root@it lwj]# docker run f7 pwd
ls: cannot access 'pwd': No such file or directory
[root@it lwj]# 
  1. 命令可被追加参数
[root@it home]# docker run f7 -lt
total 0
drwxr-xr-x   5 root root 340 Jul 12 05:14 dev
dr-xr-xr-x 237 root root   0 Jul 12 05:14 proc
drwxr-xr-x   1 root root  66 Jul 12 05:14 etc
dr-xr-xr-x  13 root root   0 Apr 16 09:28 sys
dr-xr-x---   2 root root 162 Dec  4  2020 root
drwxr-xr-x  11 root root 163 Dec  4  2020 run
drwxrwxrwt   7 root root 145 Dec  4  2020 tmp
drwxr-xr-x  20 root root 262 Dec  4  2020 var
drwxr-xr-x  12 root root 144 Dec  4  2020 usr
drwx------   2 root root   6 Dec  4  2020 lost+found
lrwxrwxrwx   1 root root   7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   2 root root   6 Nov  3  2020 home
lrwxrwxrwx   1 root root   7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root   9 Nov  3  2020 lib64 -> usr/lib64
drwxr-xr-x   2 root root   6 Nov  3  2020 media
drwxr-xr-x   2 root root   6 Nov  3  2020 mnt
drwxr-xr-x   2 root root   6 Nov  3  2020 opt
lrwxrwxrwx   1 root root   8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root   6 Nov  3  2020 srv
[root@it home]# 
  1. 可在命令的最后追加执行命令
[root@it home]# docker run f7 -lt && cd /home && pwd
total 0
drwxr-xr-x   5 root root 340 Jul 12 05:14 dev
dr-xr-xr-x 237 root root   0 Jul 12 05:14 proc
drwxr-xr-x   1 root root  66 Jul 12 05:14 etc
dr-xr-xr-x  13 root root   0 Apr 16 09:28 sys
dr-xr-x---   2 root root 162 Dec  4  2020 root
drwxr-xr-x  11 root root 163 Dec  4  2020 run
drwxrwxrwt   7 root root 145 Dec  4  2020 tmp
drwxr-xr-x  20 root root 262 Dec  4  2020 var
drwxr-xr-x  12 root root 144 Dec  4  2020 usr
drwx------   2 root root   6 Dec  4  2020 lost+found
lrwxrwxrwx   1 root root   7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   2 root root   6 Nov  3  2020 home
lrwxrwxrwx   1 root root   7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root   9 Nov  3  2020 lib64 -> usr/lib64
drwxr-xr-x   2 root root   6 Nov  3  2020 media
drwxr-xr-x   2 root root   6 Nov  3  2020 mnt
drwxr-xr-x   2 root root   6 Nov  3  2020 opt
lrwxrwxrwx   1 root root   8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root   6 Nov  3  2020 srv
/home

RUN命令

主要用于镜像构建时一些基础包安装、环境配置

[root@it lwj]# cat Dockerfile 
FROM centos
MAINTAINER wjlv4@iflytek.com
RUN yum install -y which
CMD ["w"]
CMD ["which","ls"]
# 镜像打包
[root@it lwj]# docker build -t t1:1.0 .
Sending build context to Docker daemon  2.048kB
Step 1/5 : FROM centos
 ---> 300e315adb2f
Step 2/5 : MAINTAINER wjlv4@iflytek.com
 ---> Running in 52248af28db7
Removing intermediate container 52248af28db7
 ---> 1f4e6eab8176
Step 3/5 : RUN yum install -y which
 ---> Running in 35e94501bf45
CentOS Linux 8 - AppStream                      841 kB/s | 8.1 MB     00:09    
CentOS Linux 8 - BaseOS                         986 kB/s | 3.6 MB     00:03    
CentOS Linux 8 - Extras                          13 kB/s | 9.8 kB     00:00    
Dependencies resolved.
================================================================================
 Package         Architecture     Version                Repository        Size
================================================================================
Installing:
 which           x86_64           2.21-12.el8            baseos            49 k

Transaction Summary
================================================================================
Install  1 Package

Total download size: 49 k
Installed size: 81 k
Downloading Packages:
which-2.21-12.el8.x86_64.rpm                    770 kB/s |  49 kB     00:00    
--------------------------------------------------------------------------------
Total                                            81 kB/s |  49 kB     00:00     
warning: /var/cache/dnf/baseos-f6a80ba95cf937f2/packages/which-2.21-12.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 8483c65d: NOKEY
CentOS Linux 8 - BaseOS                         1.6 MB/s | 1.6 kB     00:00    
Importing GPG key 0x8483C65D:
 Userid     : "CentOS (CentOS Official Signing Key) <security@centos.org>"
 Fingerprint: 99DB 70FA E1D7 CE22 7FB6 4882 05B5 55B3 8483 C65D
 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                        1/1 
  Installing       : which-2.21-12.el8.x86_64                               1/1 
  Running scriptlet: which-2.21-12.el8.x86_64                               1/1 
  Verifying        : which-2.21-12.el8.x86_64                               1/1 

Installed:
  which-2.21-12.el8.x86_64                                                      

Complete!
Removing intermediate container 35e94501bf45
 ---> 4bf8b8b4a058
Step 4/5 : CMD ["w"]
 ---> Running in 8ab9e716f85e
Removing intermediate container 8ab9e716f85e
 ---> 99500f570573
Step 5/5 : CMD ["which","ls"]
 ---> Running in c9a4c4164472
Removing intermediate container c9a4c4164472
 ---> f77a0f654e0c
Successfully built f77a0f654e0c
Successfully tagged t1:1.0
[root@it lwj]# 

RUNCMDENTRYPOINT`区别?

  1. RUN在构建镜像的时候执行,而CMD在容器运行的时候执行
  2. 无论是CMD还是ENTRYPOINT都只会运行最后一条
  3. CMD的命令可以在容器运行时被替换掉(不支持追加参数)
  4. ENTRYPOINT会把容器执行时的参数当作命令的追加参数(不会被替代)

总结

docker基础入门

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/30608.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信