Docker 使用指南 —— 基本操作

牧云@^-^@ 提交于 2021-02-19 11:39:10

Docker 是一个能够把开发应用程序自动部署到容器的开源引擎。它由Docker公司的团队编写,基于Apache 2.0开源协议授权。它提供了一个简单、轻量的建模方式,使开发生命周期更高效快速,鼓励了面向服务的架构设计。Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器(LXC)等技术。在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。

Docker 的特点:

  1. 更快速的交付和部署
  2. 更高效的虚拟化
  3. 更轻松的迁移和扩展
  4. 更简单的管理
  • 容器技术与传统虚拟机性能对比

  • Docker与虚拟机建构对比

Docker 容器本质上是宿主机上的一个进程。Docker 通过 namespace 实现了资源隔离,通过 cgroups 实现了资源的限制,通过写时复制机制(copy-on-write)实现了高效的文件操作。

Docker有五个命名空间:进程、网络、挂载、宿主和共享内存,为了隔离有问题的应用,Docker运用Namespace将进程隔离,为进程或进程组创建已隔离的运行空间,为进程提供不同的命名空间视图。这样,每一个隔离出来的进程组,对外就表现为一个container(容器)。需要注意的是,Docker让用户误以为自己占据了全部资源,但这并不是”虚拟机”。

Docker 中的三个概念:镜像,容器,仓库

  1. 镜像(image):Docker 镜像就是一个只读的模板,镜像可以用来创建 Docker 容器。Docker 提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。
    镜像是一种文件结构。Dockerfile中的每条命令都会在文件系统中创建一个新的层次结构,文件系统在这些层次上构建起来,镜像就构建于这些联合的文件系统之上。Docker官方网站专门有一个页面来存储所有可用的镜像,网址是:index.docker.io

  2. 容器( Container):容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。可以把容器看做是一个简易版的 Linux 环境,Docker 利用容器来运行应用。镜像是只读的,容器在启动的时候创建一层可写层作为最上层。

  3. 仓库:仓库是集中存放镜像文件的场所,仓库注册服务器(Registry)上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。目前,最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。

Docker仓库用来保存我们的images,当我们创建了自己的image之后我们就可以使用push命令将它上传到公有或者私有仓库,这样下次要在另外一台机器上使用这个image时候,只需要从仓库上pull下来就可以了。Docker 仓库的概念跟 Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。

一.安装 Docker

本次实验环境:腾讯云服务器 CentOS 6.7 x86_64

前提条件:
Docker运行对内核要求比较高,因此一般建议直接在Ubuntu这样的平台运行。但作为一个容器标准,Docker也是支持其他如CentOS, Mac OS X, Windows等平台。目前Docker支持以下版本CentOS:

  • CentOS 7(64位)
  • CentOS 6.5(64位)及以后
  • 在运行CentOS 6.5及以后版本时,需要内核版本>=2.6.32-431,因为这些内核包含了运行Docker的一些特定修改。

Docker默认使用AUFS作为存储驱动,但是AUFS并没有被包括在Linux的主线内核中。CentOS中可以使用Device Mapper作为存储驱动,这是在2.6.9内核版本引入的新功能。我们需要先确认是否启用该功能:

CentOS 7

Docker RPM包已经包含在CentOS-Extra仓库中,所以我们可以直接使用Yum安装:

# yum install docker

CentOS 6.6

需要注意的是,CentOS6.6中,已经有一个同名docker的可执行系统程序包。所以Docker RPM包命名为docker-io,我们先卸掉docker。

# yum -y remove docker

第三步 Install Docker-IO

# yum -y install docker-io

这样完成了Docker的安装。

# /etc/init.d/docker start #启动docker
# docker info #查看 docker 基本信息

二. Docker 基本操作

# docker run -d --name mynginx nginx   #启动nginx镜像,没有会自动pull
# docker stop bfd094233f96   #停止一个容器,根据容器 id 进行删除
# docker rm bfd094233f96   #删除一个容器
# docker attach d20f3dc6cd92  #进入一个正在运行的容器

-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上,
-i 则让容器的标准输入保持打开。
–name 使用一个自定义的名字

此命令不太好用,建议使用以下命令进入容器:

[root@localhost docker] docker inspect --format "{{.State.Pid}}" mynginx  #获取容器pid 19769
[root@localhost docker] nsenter --target 19769 --mount --uts --ipc --net --pid  #进入容器(推荐方法) docker run -d -p 91:80 --name mynginx2 nginx # -p 指定端口映射,将80映射为host的91 

存储镜像:

# docker save -o ubuntu_14.04.tar ubuntu:14.04 

载入镜像:

# docker load < ubuntu_14.04.tar  或者使用 
# cat ubuntu.tar |  docker import - test/ubuntu:v1.0 

移除本地镜像:

# docker rmi training/sinatra
清理所有未打过标签的本地镜像:

# docker rmi $(docker images -q -f "dangling=true")
其中 -q 和 -f 是 quiet,–filter 的缩写, 完整的命令其实可以写着下面这样,是不是更容易理解一点?

# docker rmi $(docker images --quiet --filter "dangling=true")
注: 容器是否会长久运行,是和docker run指定的命令有关,和 -d 参数无关。

要获取容器的输出信息,可以通过 docker logs 命令。
# docker logs [container ID or NAMES]

删除容器:
# docker rm 默认并不会删除运行中的容器

有关容器和镜像的底层信息:
# docker inspect container/image

可以查看:
容器实例的IP地址
端口绑定列表
特定端口映射的搜索
收集配置的详细信息

从容器内复制文件到指定的路径上:
# docker cp container:path hostpath

使用Dockerfile来构建镜像:
# docker build [options] PATH | URL

–rm=true表示构建成功后,移除所有中间容器
–no-cache=false表示在构建过程中不使用缓存

 

更多信息:https://www.w3cschool.cn/use_docker/

 

四、Docker compose项目

使用docker就不得不提Docker Compose,它是 Docker 官方编排(Orchestration)项目之一,负责快速在集群中部署分布式应用。它允许用户通过一个单独的 docker-compose. 
yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。就是说,你可以通过docker-compose.yml 模板文件来定义一个服务器集群,服务器集群中的每个服务器就是一个容器,可以配置多个容器之间的网络连接、端口,容器服务器名称、服务器中运行的镜像、服务器的环境配置、启动命令等。使用的镜像,可以手动拉取镜像,也可以自动以docker-compose.yml 构建环境后自动拉取。

 

 

 

Compose 中有两个重要的概念:

服务(service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。

项目(project):由一组关联的应用容器组成的一个完整业务单元,在 dockercompose.yml 文件中定义。

 

五、Docker compose安装与卸载

Compose 目前支持 Linux 和 Mac OS 平台,两者的安装过程大同小异。安装 Compose 之前,要先安装 Docker(需要 Docker Engine 1.7.1+),Compose 可以通过 Python 的 pip 工具进行安装,可以直接下载编译好的二进制文件使用,甚至直接运行在 Docker 容器中。

1)首先安装epel扩展源:

sudo yum -y install epel-release

2)然后安装python-pip

sudo yum -y install python-pip

pip install docker-compose

3)版本查询

docker-compose –v

4)卸载

pip uninstall docker-compose

 

六、Docker 命令查询

Docker 命令有两大类,客户端命令和服务端命令。前者是主要的操作接口,后者用来启动 Docker daemon。

客户端命令:基本命令格式为  docker [OPTIONS] COMMAND [arg...] ;

服务端命令:基本命令格式为  docker daemon [OPTIONS] 。

可以通过 man docker 或 docker help 来查看这些命令。

1)服务端命令:docker daemon [OPTIONS] ,[OPTIONS] 的选项有:

--api-cors-header="":CORS 头部域,默认不允许 CORS,要允许任意的跨域访问,可以指定为 “*”; 
--authorization-plugin="":载入认证的插件; 
-b="":将容器挂载到一个已存在的网桥上。指定为 'none' 时则禁用容器的网络,与 --bip 选项互斥; 
--bip="":让动态创建的 docker0 网桥采用给定的 CIDR 地址; 与 -b 选项互斥; 
--cgroup-parent="":指定 cgroup 的父组,默认 fs cgroup 驱动为/docker ,systemd cgroup 驱动为 system.slice ; 
--cluster-store="":构成集群(如 Swarm)时,集群键值数据库服务地址; 
--cluster-advertise="":构成集群时,自身的被访问地址,可以为host:port 或 interface:port ; 
--cluster-store-opt="":构成集群时,键值数据库的配置选项; 
--config-file="/etc/docker/daemon.json":daemon 配置文件路径; 
--containerd="":containerd 文件的路径; 
-D, --debug=true|false:是否使用 Debug 模式。缺省为 false; 
--default-gateway="":容器的 IPv4 网关地址,必须在网桥的子网段内; 
--default-gateway-v6="":容器的 IPv6 网关地址; 
--default-ulimit=[]:默认的 ulimit 值; 
--disable-legacy-registry=true|false:是否允许访问旧版本的镜像仓库服务器; 
--dns="":指定容器使用的 DNS 服务器地址; 
--dns-opt="":DNS 选项; 
--dns-search=[]:DNS 搜索域; 
--exec-opt=[]:运行时的执行选项; 
--exec-root="":容器执行状态文件的根路径,默认为 /var/run/docker ; 
--fixed-cidr="":限定分配 IPv4 地址范围; 
--fixed-cidr-v6="":限定分配 IPv6 地址范围; 
-G, --group="":分配给 unix 套接字的组,默认为 docker ; 
-g, --graph="":Docker 运行时的根路径,默认为 /var/lib/docker ; 
-H, --host=[]:指定命令对应 Docker daemon 的监听接口,可以为 unix 套接字(unix:///path/to/socket),文件句柄(fd://socketfd)或 tcp 套接字(tcp://[host[:port]]),默认为 unix:///var/run/docker.sock; 
--icc=true|false:是否启用容器间以及跟 daemon 所在主机的通信。默认为true。 
--insecure-registry=[]:允许访问给定的非安全仓库服务; 
--ip="":绑定容器端口时候的默认 IP 地址。缺省为 0.0.0.0; 
--ip-forward=true|false:是否检查启动在 Docker 主机上的启用 IP 转发服务,默认开启。注意关闭该选项将不对系统转发能力进行任何检查修改; 
--ip-masq=true|false:是否进行地址伪装,用于容器访问外部网络,默认开启; 
--iptables=true|false:是否允许 Docker 添加 iptables 规则。缺省为 true; 
--ipv6=true|false:是否启用 IPv6 支持,默认关闭;

-l, --log-level="debug|info|warn|error|fatal":指定日志输出级别; 
--label="[]":添加指定的键值对标注; 
--log-driver="jsonfile|syslog|journald|gelf|fluentd|awslogs|splunk|etwlogs|gcplogs|none":指定日志后端驱动,默认为 json-file; 
--log-opt=[]:日志后端的选项; 
--mtu=VALUE:指定容器网络的 mtu; 
-p="":指定 daemon 的 PID 文件路径。缺省为 /var/run/docker.pid ; 
--raw-logs:输出原始,未加色彩的日志信息; 
--registry-mirror=://:指定 docker pull 时使用的注册服务器镜像地址; 
-s, --storage-driver="":指定使用给定的存储后端; 
--selinux-enabled=true|false:是否启用 SELinux 支持。缺省值为 false。SELinux 目前尚不支持 overlay 存储驱动; 
--storage-opt=[]:驱动后端选项; 
--tls=true|false:是否对 Docker daemon 启用 TLS 安全机制,默认为否; 
--tlscacert= /.docker/ca.pem:TLS CA 签名的可信证书文件路径; 
--tlscert= /.docker/cert.pem:TLS 可信证书文件路径; 
--tlscert= /.docker/key.pem:TLS 密钥文件路径; 
--tlsverify=true|false:启用 TLS 校验,默认为否; 
--userland-proxy=true|false:是否使用用户态代理来实现容器间和出容器的回环通信,默认为 true; 
--userns-remap=default|uid:gid|user:group|user|uid:指定容器的用户命名空间,默认是创建新的 UID 和 GID 映射到容器内进程。

 

2)客户端命令:docker [OPTIONS] COMMAND [arg...] ;[OPTIONS] 的选项有:

--config="":指定客户端配置文件,默认为 /.docker ; 
-D=true|false:是否使用 debug 模式。默认不开启; 
-H, --host=[]:指定命令对应 Docker daemon 的监听接口,可以为 unix 套接字(unix:///path/to/socket),文件句柄(fd://socketfd)或 tcp 套接字(tcp://[host[:port]]),默认为 unix:///var/run/docker.sock; 
-l, --log-level="debug|info|warn|error|fatal":指定日志输出级别; 
--tls=true|false:是否对 Docker daemon 启用 TLS 安全机制,默认为否; 
--tlscacert= /.docker/ca.pem:TLS CA 签名的可信证书文件路径; 
--tlscert= /.docker/cert.pem:TLS 可信证书文件路径; 
--tlscert= /.docker/key.pem:TLS 密钥文件路径; 
--tlsverify=true|false:启用 TLS 校验,默认为否。

 

3)客户端命令:docker [OPTIONS] COMMAND [arg...] ;COMMAND的选项有:

可以使用:docker   COMMAND  --help 来查看每个命令的具体用法

attach:依附到一个正在运行的容器中; 
build:从一个 Dockerfile 创建一个镜像; 
commit:从一个容器的修改中创建一个新的镜像; 
cp:在容器和本地宿主系统之间复制文件中; 
create:创建一个新容器,但并不运行它; 
diff:检查一个容器内文件系统的修改,包括修改和增加; 
events:从服务端获取实时的事件;

exec:在运行的容器内执行命令; 
export:导出容器内容为一个 tar 包; 
history:显示一个镜像的历史信息; 
images:列出存在的镜像; 
import:导入一个文件(典型为 tar 包)路径或目录来创建一个本地镜像; 
info:显示一些相关的系统信息; 
inspect:显示一个容器的具体配置信息; 
kill:关闭一个运行中的容器 (包括进程和所有相关资源); 
load:从一个 tar 包中加载一个镜像; 
login:注册或登录到一个 Docker 的仓库服务器; 
logout:从 Docker 的仓库服务器登出; 
logs:获取容器的 log 信息; 
network:管理 Docker 的网络,包括查看、创建、删除、挂载、卸载等; 
node:管理 swarm 集群中的节点,包括查看、更新、删除、提升/取消管理节点等; 
pause:暂停一个容器中的所有进程; 
port:查找一个 nat 到一个私有网口的公共口; 
ps:列出主机上的容器; 
pull:从一个Docker的仓库服务器下拉一个镜像或仓库; 
push:将一个镜像或者仓库推送到一个 Docker 的注册服务器; 
rename:重命名一个容器; 
restart:重启一个运行中的容器; 
rm:删除给定的若干个容器; 
rmi:删除给定的若干个镜像; 
run:创建一个新容器,并在其中运行给定命令; 
save:保存一个镜像为 tar 包文件; 
search:在 Docker index 中搜索一个镜像; 
service:管理 Docker 所启动的应用服务,包括创建、更新、删除等; 
start:启动一个容器; 
stats:输出(一个或多个)容器的资源使用统计信息; 
stop:终止一个运行中的容器; 
swarm:管理 Docker swarm 集群,包括创建、加入、退出、更新等; 
tag:为一个镜像打标签; 
top:查看一个容器中的正在运行的进程信息; 
unpause:将一个容器内所有的进程从暂停状态中恢复; 
update:更新指定的若干容器的配置信息;

version:输出 Docker 的版本信息; 
volume:管理 Docker volume,包括查看、创建、删除等; 
wait:阻塞直到一个容器终止,然后输出它的退出符。

 

4)Docker 删除命令实例

a)删除一个容器

docker rm <containerID>

b)强制删除一个容器

docker rm -f <containerID>

c)强制删除全部容器

docker rm -f $(docker ps -aq)

d)删除一个镜像:

docker rmi <imageID>

e)强制删除一个镜像:

docker rmi -f <imageID>

f)强制删除全部镜像

docker rmi -f $(docker images -q)

 

5)一张图总结 Docker 的命令

container事件状态图 
image

Docker 命令分布图:

image

 

七、Docker Compose命令查询

对于 Compose 来说,大部分命令的对象既可以是项目本身,也可以指定为项目中的服务或者容器。如果没有特别的说明,命令对象将是项目,这意味着项目中所有的服务都会受到命令影响。执行 docker-compose [COMMAND] --help 或者 docker-compose help [COMMAND] 可以查看具体某个命令的使用格式。

Compose 命令的基本的使用格式是:

docker-compose [-f=<arg>...] [options] [COMMAND] [ARGS...]

 

[options] 选项:

-f, --file FILE 指定使用的 Compose 模板文件,默认为 dockercompose.yml ,可以多次指定。 
-p, --project-name NAME 指定项目名称,默认将使用所在目录名称作为项目名。 
--x-networking 使用 Docker 的可拔插网络后端特性(需要 Docker 1.9 及以后版本)。 
--x-network-driver DRIVER 指定网络后端的驱动,默认为 bridge (需要 Docker 1.9 及以后版本)。 
--verbose 输出更多调试信息。 
-v, --version 打印版本并退出。

[COMMAND] 选项:

1)build:格式为 docker-compose build [options] [SERVICE...]

构建(重新构建)项目中的服务容器。服务容器一旦构建后,将会带上一个标记名,例如对于 web 项目中的一个 db 容器,可能是 web_db。可以随时在项目目录下运行 docker-compose build 来重新构建服务。

它的[options] 选项包括:

--force-rm 删除构建过程中的临时容器。 
--no-cache 构建镜像过程中不使用 cache(这将加长构建过程)。 
--pull 始终尝试通过 pull 来获取更新版本的镜像。

2)kill:格式为 docker-compose kill [options] [SERVICE...]

通过发送 SIGKILL 信号来强制停止服务容器。支持通过 -s 参数来指定发送的信号,例如通过如下指令发送 SIGINT 信号:docker-compose kill -s SIGINT

3)logs:格式为 docker-compose logs [options] [SERVICE...]

查看服务容器的输出。默认情况下,docker-compose 将对不同的服务输出使用不同的颜色来区分。可以通过 --no-color 来关闭颜色。该命令在调试问题的时候十分有用。

4)pause:格式为 docker-compose pause [SERVICE...] 
暂停一个服务容器。

5)port:格式为 docker-compose port [options] SERVICE PRIVATE_PORT 
打印某个容器端口所映射的公共端口。 
[options] 选项: 
--protocol=proto 指定端口协议,tcp(默认值)或者 udp。 
--index=index 如果同一服务存在多个容器,指定命令对象容器的序号(默认为 1)。

6)ps:格式为 docker-compose ps [options] [SERVICE...] 
列出项目中目前的所有容器。

选项: 
-q 只打印容器的 ID 信息。

7)pull:格式为 docker-compose pull [options] [SERVICE...] 
拉取服务依赖的镜像。 
选项: 
--ignore-pull-failures 忽略拉取镜像过程中的错误。

8)restart:格式为 docker-compose restart [options] [SERVICE...] 
重启项目中的服务。 
选项: 
-t, --timeout TIMEOUT 指定重启前停止容器的超时(默认为 10 秒)。

9)rm:格式为 docker-compose rm [options] [SERVICE...]

删除所有(停止状态的)服务容器。推荐先执行 docker-compose stop 命令来停止容器。 
选项: 
-f, --force 强制直接删除,包括非停止状态的容器。一般尽量不要使用该选项。 
-v 删除容器所挂载的数据卷。

10)run:格式为 docker-compose run [options] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...] 
在指定服务上执行一个命令。 
例如: 
$ docker-compose run ubuntu ping docker.com

将会启动一个 ubuntu 服务容器,并执行 ping docker.com 命令。

默认情况下,如果存在关联,则所有关联的服务将会自动被启动,除非这些服务已经在运行中。 
该命令类似启动容器后运行指定的命令,相关卷、链接等等都将会按照配置自动创建。 
两个不同点:

  • 给定命令将会覆盖原有的自动运行命令;
  • 不会自动创建端口,以避免冲突。

如果不希望自动启动关联的容器,可以使用 --no-deps 选项,例如

$ docker-compose run --no-deps web python manage.py shell 
将不会启动 web 容器所关联的其它容器。 
[options] 选项:

-d 后台运行容器。 
--name NAME 为容器指定一个名字。 
--entrypoint CMD 覆盖默认的容器启动指令。 
-e KEY=VAL 设置环境变量值,可多次使用选项来设置多个环境变量。 
-u, --user="" 指定运行容器的用户名或者 uid。 
--no-deps 不自动启动关联的服务容器。 
--rm 运行命令后自动删除容器, d 模式下将忽略。 
-p, --publish=[] 映射容器端口到本地主机。 
--service-ports 配置服务端口并映射到本地主机。 
-T 不分配伪 tty,意味着依赖 tty 的指令将无法运行。

11)scale:格式为 docker-compose scale [options] [SERVICE=NUM...] 
设置指定服务运行的容器个数。通过 service=num 的参数来设置数量。例如: 
$ docker-compose scale web=3 db=2 
将启动 3 个容器运行 web 服务,2 个容器运行 db 服务。一般的,当指定数目多于该服务当前实际运行容器,将新创建并启动容器;反之,停止容器。 
选项: 
-t, --timeout TIMEOUT 停止容器时候的超时(默认为 10 秒)。

12)start:格式为 docker-compose start [SERVICE...] 
启动已经存在的服务容器。

13)stop:格式为 docker-compose stop [options] [SERVICE...]

停止已经处于运行状态的容器,但不删除它。通过 docker-compose start 可以再次启动这些容器。 
选项: 
-t, --timeout TIMEOUT 停止容器时候的超时(默认为 10 秒)。

14)unpause:格式为 docker-compose unpause [SERVICE...] 。 
恢复处于暂停状态中的服务。

15)up:格式为 docker-compose up [options] [SERVICE...] 。 
该命令十分强大,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。 
链接的服务都将会被自动启动,除非已经处于运行状态。可以说,大部分时候都可以直接通过该命令来启动一个项目。 
默认情况, docker-compose up 启动的容器都在前台,控制台将会同时打印所有容器的输出信息,可以很方便进行调试。当通过 Ctrl-C 停止命令时,所有容器将会停止。 
如果使用 docker-compose up -d ,将会在后台启动并运行所有的容器。一般推荐生产环境下使用该选项。 
默认情况,如果服务容器已经存在, docker-compose up 将会尝试停止容器,然后重新创建(保持使用 volumes-from 挂载的卷),以保证新启动的服务匹配docker-compose.yml 文件的最新内容。如果用户不希望容器被停止并重新创建,可以使用 docker-compose up --no-recreate 。这样将只会启动处于停止状态的容器,而忽略已经运行的服务。如果用户只想重新部署某个服务,可以使用docker-compose up --no-deps -d <SERVICE_NAME> 来重新创建服务并后台停止旧服务,启动新服务,并不会影响到其所依赖的服务。

[options] 选项: 
-d 在后台运行服务容器。

--no-color 不使用颜色来区分不同的服务的控制台输出。 
--no-deps 不启动服务所链接的容器。 
--force-recreate 强制重新创建容器,不能与 --no-recreate 同时使用。 
--no-recreate 如果容器已经存在了,则不重新创建,不能与 --forcerecreate同时使用。 
--no-build 不自动构建缺失的服务镜像。 
-t, --timeout TIMEOUT 停止容器时候的超时(默认为 10 秒)。

16)migrate-to-labels:格式为 docker-compose migrate-to-labels 。 
重新创建容器,并添加 label。 
主要用于升级 1.2 及更早版本中创建的容器,添加缺失的容器标签。实际上,最彻底的办法当然是删除项目,然后重新创建。 
17)version:格式为 docker-compose version 。 
打印版本信息。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!