Docker快速入门

  • 一、Docker介绍
    • 1.1 Docker背景
    • 1.2 Docker概念
    • 1.3 Docker的优势
    • 1.4 Docker的三个基本概念
  • 二、Docker的安装和使用
    • 2.1 安装依赖包
    • 2.2 安装Docker
  • 三、启动Docker并查看状态
  • 四、升级Docker
    • 4.1 移除系统中原有的rpm包
    • 4.2 验证是否已经删除
    • 4.3 安装最新的Docker
    • 4.4 查看已经升级的Docker版本
  • 五、配置国内镜像源
  • 六、Docker简单运用
  • 七、Docker组件之间工作 (与简单运用关联)
  • 八、Docker常用命令
    • 8.1 镜像操作
    • 8.2 容器操作
  • 九、Docker架构
    • Docker镜分层结构
    • Docker镜像加载原理
  • 十、创建镜像
    • 10.1 更新镜像
    • 10.2 构建镜像
  • 十一、Dockerfile
    • 11.1 简介
    • 11.2 语法规则
    • 11.3 常用的指令
    • 11.4 自定义centos
    • 11.5 创建Tomcat镜像
  • 十二、将本地的镜像发布到阿里云
  • 十三、网络操作
    • 13.1 Namespace
    • 13.2 网络模式
      • None模式
      • Container模式
      • Host模式
      • Bridge模式
    • 13.3 端口映射
    • 13.4 容器互联
    • 13.5 网络支持
  • 十四、仓库与数据管理
    • 1.共有仓库
    • 2.私有仓库
    • 3.数据存储(共享)
      • 数据卷
      • 数据卷容器
  • 十五、网络与集群管理
    • 1.Pipework原理解析
    • 2.Open vSwitch简介
    • 3.OVS划分VLAN
    • 4.Shipyard
    • 5.harbor
  • 十六、自定义 docker0 桥的网络属性信息

建议先收藏,有需要就拿出来,耐心看,一定有所收获,好东西都需要时间去付出得来的。

一、Docker介绍

1.1 Docker背景

产生背景:
(1)开发和运维、测试因为环境不同而导致的矛盾(操作系统不同、软件环境不同、应用配置的不同等)
(2)集群环境下每台服务器都需要配置相同的环境,成本巨大
(3)充分利用服务器机器的资源,避免浪费

1.2 Docker概念

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口

沙箱:
为运行中的程序提供的隔离环境。通常是作为一些来源不可信、具破坏力或无法判定程序意图的程序提供实验之用。

作用:
(1)将软件环境安装并且配置好,打包成一个镜像image,然后将该镜像发布出去(docker仓库)。
其他使用者可以在仓库中下载并使用这个镜像,通过docker运行这个镜像,可以获取相同的环境。

(2)简化环境部署和配置,实现一次构建,处处运行。

1.3 Docker的优势

Docker相比于传统虚拟化方式具有更多的优势:

  • docker 启动快速属于秒级别。虚拟机通常需要几分钟去启动
    - docker 需要的资源更少, docker 在操作系统级别进行虚拟化, docker 容器和内核交互,几乎没有性能损耗,性能优于通过 Hypervisor 层与内核层的虚拟化。Docker在底层的宿主机上生成的容器,传统虚拟化方式模拟的是完整的一个操作系统
    - docker 更轻量, docker 的架构可以共用一个内核与共享应用程序库,所占内存极小。同样的硬件环境, Docker 运行的镜像数远多于虚拟机数量,对系统的利用率非常高
    - docker 隔离性更弱, docker 属于进程之间的隔离,虚拟机可实现系统级别隔离。Docker与宿主机共享OS,虚拟化方式的宿主机和VM各自运行OS
    - 安全性: docker 的安全性也更弱。 Docker 的租户 root 和宿主机 root 等同,一旦容器内的用户从普通用户权限提升为root权限,它就直接具备了宿主机的root权限,进而可进行无限制的操作。虚拟机租户 root 权限和宿主机的 root 虚拟机权限是分离的,并且虚拟机利用如 Intel 的 VT-d 和 VT-x 的 ring-1 硬件隔离技术,这种隔离技术可以防止虚拟机突破和彼此交互,而容器至今还没有任何形式的硬件隔离,这使得容器容易受到攻击
    - 可管理性: docker 的集中化管理工具还不算成熟。各种虚拟化技术都有成熟的管理工具,例如 VMware vCenter 提供完备的虚拟机管理能力
    高可用和可恢复性: docker 对业务的高可用支持是通过快速重新部署实现的。虚拟化具备负载均衡,高可用,容错,迁移和数据保护等经过生产实践检验的成熟保障机制, VMware 可承诺虚拟机 99.999% 高可用,保证业务连续性
    快速创建、删除:虚拟化创建是分钟级别的, Docker 容器创建是秒级别的, Docker 的快速迭代性,决定了无论是开发、测试、部署都可以节约大量时间
    交付、部署:虚拟机可以通过镜像实现环境交付的一致性,但镜像分发无法体系化。 Docker 在 Dockerfile 中记录了容器构建过程,可在集群中实现快速分发和快速部署
特性 容器 虚拟机
启动 秒级 分钟级
硬盘使用 一般为MB 一般为GB
性能 接近原生 弱于
系统支持量 单机支持上千个容器 一般是几十个

1.4 Docker的三个基本概念


从上图我们可以看到,Docker 中包括三个基本的概念:
简要概括就是:
Image(镜像):将软件环境打包好的模板,用来创建容器,一个镜像可以创建N个容器
Container(容器):镜像运行后产生的实例称为容器,每运行一次镜像就会产生一个容器,容器之间相互是隔离的。
Repository(仓库):用来保存镜像,仓库中含有许多的镜像,每个镜像都有不同的标签tag。

详细概括就是:
镜像是 Docker 运行容器的前提,仓库是存放镜像的场所,可见镜像更是 Docker 的核心。

Image (镜像)
镜像是静态的、可以被用户互相分享的文件。我们玩过双系统和虚拟机的人都知道,首先你需要一个.iso镜像,才能安装系统。Docker中的镜像也是这个东西,镜像是静态的,你不能对他操作,只能pull别人的镜像或者push自己的镜像。

Docker镜像可以看作是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

Docker镜像的特点
Docker镜像都是只读的,当容器启动时,一个新的可写层加载到镜像的顶部
这一层就是我们通常说的容器层,容器之下的都叫镜像层

容器(Container)
前面说过,镜像是静态不可操作的,只能被分享和下载,那什么是能被操作的呢?就是容器里!容器可以理解为镜像的动态状态,也就是我们虚拟机中系统装好后的状态,如果要保存修改,就需要将当前容器封装成一个新的镜像,这样下次启动这个新的镜像后之前作出的修改还都在。

仓库(Repository)
Docker中的仓库很像git的代码仓库,你可以pull自己之前push到自己仓库的镜像到本地,也可以pull别人push到公共仓库的镜像到自己本地。说白了就是百度云盘,你可以上传(push)自己做好环境的Docker上去,也可以下载(pull)自己云端的镜像到本地。同时,我们知道百度云最大的特点就是分享,类比Docker,如果你得到百度云分享链接(别人的镜像名字、标签和别人的用户名),你还可以下载(pull)别人分享的镜像到自己的本地,别人也可以下载(pull)你的镜像,因为Docker仓库都是公共的。当然,每个免费用户有一个名额把自己的一个镜像设为私有,也就是禁止被分享给别人,类比百度云上你自己保存的后没有去生成分享链接

二、Docker的安装和使用

Docker 的安装和使用有一些前提条件,主要体现在体系架构和内核的支持上。对于体系架构,Docker 只支持的 X86-64,目前不支持X86 ,其他体系架构的支持则一直在不断地完善和推进中。

  • 查询内核版本
  • uname -r
  • Linux内核需开启cgroups和namespace功能
    开启cgroups服务(#CentOS7系统需要安装libcgroup-tools包,才有cgroup配置命令yum install-y libcgroup-tools.x86_64)
    #service cqconfig start
    设置开机启动
    #chkconfig cqconfig on

Docker 分为 CE 和 EE 两大版本。 CE 即社区版, EE 即企业版(付费)。

我们在安装前可以参看官方文档获取最新的 Docker 支持情况,官方文档在这里:

https://docs.docker.com/install/

Docker 对于内核支持的功能,即内核的配置选项也有一定的要求(比如必须开启 Cgroup 和 Namespace 相关选项,以及其他的网络和存储驱动等), Docker 源码中提供了一个检测脚本来检测和指导内核的配置,脚本链接在这里:

https://raw.githubusercontent.com/docker/docker/master/contrib/check-config.sh

在满足前提条件后,安装就变得非常的简单了。

Docker CE 的安装请参考官方文档:

MacOS:https://docs.docker.com/docker-for-mac/install/
Windows:https://docs.docker.com/docker-for-windows/install/
Ubuntu:https://docs.docker.com/install/linux/docker-ce/ubuntu/
Debian:https://docs.docker.com/install/linux/docker-ce/debian/
CentOS:https://docs.docker.com/install/linux/docker-ce/centos/
Fedora:https://docs.docker.com/install/linux/docker-ce/fedora/
其他 Linux 发行版:https://docs.docker.com/install/linux/docker-ce/binaries/

这里我们以 CentOS7 作为本文的演示。

环境准备

阿里云服务器(1核2G,1M带宽)
CentOS 7.4 64位

由于 Docker-CE 支持 64 位版本的 CentOS7 ,并且要求内核版本不低于 3.10

2.1 安装依赖包

执行以下安装命令去安装依赖包:

yum install -y yum-utils \device-mapper-persistent-data \lvm2

2.2 安装Docker

第一种安装方式:
Docker 软件包已经包括在默认的 CentOS-Extras 软件源里。因此想要安装 docker,只需要运行下面的 yum 命令

yum install docker


第二种安装方式:
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,CentOS 系统上可以使用这套脚本安装:

curl -fsSL get.docker.com -o get-docker.sh
sh get-docker.shcurl -fsSL https://get.docker.com/ | sh

具体可以参看 docker-install 的脚本:
https://github.com/docker/docker-install

三、启动Docker并查看状态

基本操作:
docker version #查看docker版本
systemctl start docker #启动docker
systemctl stop docker #停止docker
systemctl status docker #查看状态
systemctl restart docker #重启
systemctl enable docker #设置开机自动启动

[root@aliyun ~]# systemctl start docker
[root@aliyun ~]# systemctl status docker


查看docker 当前版本

[root@aliyun ~]# docker version

四、升级Docker

[root@aliyun ~]# rpm -qa | grep docker
docker-common-1.13.1-162.git64e9980.el7.centos.x86_64
docker-1.13.1-162.git64e9980.el7.centos.x86_64
docker-client-1.13.1-162.git64e9980.el7.centos.x86_64

4.1 移除系统中原有的rpm包

三个都要卸载干净,卸载之后 rpm -qa | grep docker 验证[root@aliyun ~]# yum remove docker-1.13.1-162.git64e9980.el7.centos.x86_64
Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-managerThis system is not registered with an entitlement server. You can use subscription-manager to register.Resolving Dependencies
--> Running transaction check
---> Package docker.x86_64 2:1.13.1-162.git64e9980.el7.centos will be erased
--> Finished Dependency ResolutionDependencies Resolved=====================================================================================================================Package             Arch                Version                                          Repository            Size
=====================================================================================================================
Removing:docker              x86_64              2:1.13.1-162.git64e9980.el7.centos               @extras               65 MTransaction Summary
=====================================================================================================================
Remove  1 PackageInstalled size: 65 M
Is this ok [y/N]: y
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transactionErasing    : 2:docker-1.13.1-162.git64e9980.el7.centos.x86_64                                                  1/1
warning: /etc/sysconfig/docker-storage saved as /etc/sysconfig/docker-storage.rpmsaveVerifying  : 2:docker-1.13.1-162.git64e9980.el7.centos.x86_64                                                  1/1 Removed:docker.x86_64 2:1.13.1-162.git64e9980.el7.centos                                                                   Complete!

4.2 验证是否已经删除

[root@aliyun ~]# rpm -qa | grep docker
[root@aliyun ~]# docker
-bash: /usr/bin/docker: No such file or directory

4.3 安装最新的Docker

[root@aliyun ~]# curl -fsSL https://get.docker.com/ | sh
# Executing docker install script, commit: 26ff363bcf3b3f5a00498ac43694bf1c7d9ce16c
+ sh -c 'yum install -y -q yum-utils'
Package yum-utils-1.1.31-54.el7_8.noarch already installed and latest version
+ sh -c 'yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo'
Loaded plugins: fastestmirror, langpacks, product-id, subscription-managerThis system is not registered with an entitlement server. You can use subscription-manager to register.adding repo from: https://download.docker.com/linux/centos/docker-ce.repo
grabbing file https://download.docker.com/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo
repo saved to /etc/yum.repos.d/docker-ce.repo
+ '[' stable '!=' stable ']'
+ sh -c 'yum makecache'
Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-managerThis system is not registered with an entitlement server. You can use subscription-manager to register.Loading mirror speeds from cached hostfile* base: mirrors.cloud.aliyuncs.com* extras: mirrors.cloud.aliyuncs.com* updates: mirrors.cloud.aliyuncs.com
base                                                                                          | 3.6 kB  00:00:00
docker-ce-stable                                                                              | 3.5 kB  00:00:00
epel                                                                                          | 4.7 kB  00:00:00
extras                                                                                        | 2.9 kB  00:00:00
mysql-connectors-community                                                                    | 2.5 kB  00:00:00
mysql-tools-community                                                                         | 2.5 kB  00:00:00
mysql57-community                                                                             | 2.5 kB  00:00:00
updates                                                                                       | 2.9 kB  00:00:00
(1/17): docker-ce-stable/x86_64/filelists_db                                                  |  21 kB  00:00:00
(2/17): docker-ce-stable/x86_64/primary_db                                                    |  45 kB  00:00:00
(3/17): epel/x86_64/prestodelta                                                               |  822 B  00:00:00
(4/17): extras/7/x86_64/filelists_db                                                          | 217 kB  00:00:00
(5/17): epel/x86_64/other_db                                                                  | 3.3 MB  00:00:00
(6/17): extras/7/x86_64/other_db                                                              | 125 kB  00:00:00
(7/17): epel/x86_64/filelists_db                                                              |  12 MB  00:00:00
(8/17): docker-ce-stable/x86_64/updateinfo                                                    |   55 B  00:00:00
(9/17): mysql-connectors-community/x86_64/other_db                                            |  15 kB  00:00:00
(10/17): mysql-connectors-community/x86_64/filelists_db                                       |  78 kB  00:00:00
(11/17): mysql-tools-community/x86_64/other_db                                                |  16 kB  00:00:00
(12/17): docker-ce-stable/x86_64/other_db                                                     | 114 kB  00:00:00
(13/17): updates/7/x86_64/filelists_db                                                        | 1.7 MB  00:00:00
(14/17): mysql57-community/x86_64/other_db                                                    |  56 kB  00:00:00
(15/17): updates/7/x86_64/other_db                                                            | 249 kB  00:00:00
(16/17): mysql-tools-community/x86_64/filelists_db                                            | 246 kB  00:00:00
(17/17): mysql57-community/x86_64/filelists_db                                                | 1.0 MB  00:00:00
Metadata Cache Created
+ '[' -n '' ']'
+ sh -c 'yum install -y -q docker-ce'
warning: /var/cache/yum/x86_64/7/docker-ce-stable/packages/docker-ce-19.03.12-3.el7.x86_64.rpm: Header V4 RSA/SHA512 Signature, key ID 621e9f35: NOKEY
Public key for docker-ce-19.03.12-3.el7.x86_64.rpm is not installed
Importing GPG key 0x621E9F35:Userid     : "Docker Release (CE rpm) <docker@docker.com>"Fingerprint: 060a 61c5 1b55 8a7f 742b 77aa c52f eb6b 621e 9f35From       : https://download.docker.com/linux/centos/gpg
If you would like to use Docker as a non-root user, you should now consider
adding your user to the "docker" group with something like:sudo usermod -aG docker your-userRemember that you will have to log out and back in for this to take effect!WARNING: Adding a user to the "docker" group will grant the ability to runcontainers which can be used to obtain root privileges on thedocker host.Refer to https://docs.docker.com/engine/security/security/#docker-daemon-attack-surfacefor more information.

4.4 查看已经升级的Docker版本

[root@aliyun ~]# systemctl start docker
[root@aliyun ~]# docker version
Client: Docker Engine - CommunityVersion:           19.03.12API version:       1.40Go version:        go1.13.10Git commit:        48a66213feBuilt:             Mon Jun 22 15:46:54 2020OS/Arch:           linux/amd64Experimental:      falseServer: Docker Engine - CommunityEngine:Version:          19.03.12API version:      1.40 (minimum version 1.12)Go version:       go1.13.10Git commit:       48a66213feBuilt:            Mon Jun 22 15:45:28 2020OS/Arch:          linux/amd64Experimental:     falsecontainerd:Version:          1.2.13GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429runc:Version:          1.0.0-rc10GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dddocker-init:Version:          0.18.0GitCommit:        fec3683

五、配置国内镜像源

阿里云镜像源配置

mkdir -p /etc/docker
vim /etc/docker/daemon.json
{"registry-mirrors": ["https://duvzla6d.mirror.aliyuncs.com"]
}systemctl daemon-reload
systemctl restart docker

也可以参考其他镜像源:https://www.cnblogs.com/reasonzzy/p/11127359.html

如果是云服务器,可以使用容器镜像服务(自己的专属加速器地址),进行配置https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors

六、Docker简单运用

通过最简单的 image 文件 hello world,感受一下 Docker 的魅力吧!

我们直接运行下面的命令,将名为 hello-world 的 image 文件从仓库抓取到本地。

docker pull library/hello-world

docker pull images 是抓取 image 文件, library/hello-world 是 image 文件在仓库里面的位置,其中 library 是 image 文件所在的组, hello-world 是 image 文件的名字。

抓取成功以后,就可以在本机看到这个 image 文件了。

docker images

如下结果:
现在,可以运行 hello-world 这个 image 文件

输出这段提示以后,hello world 就会停止运行,容器自动终止。有些容器不会自动终止,因为提供的是服务,比如Mysql镜像等。

七、Docker组件之间工作 (与简单运用关联)

Docker组件是如何协作运行容器
现在我们再通过hello-world这个例子来体会一下 Docker 各个组件是如何协作的。

容器启动过程如下:

  • Docker 客户端执行 docker run 命令
  • Docker daemon 发现本地没有 hello-world 镜像
  • daemon 从 Docker Hub 下载镜像
  • 下载完成,镜像 hello-world 被保存到本地
  • Docker daemon 启动容器


我们可以通过docker images 可以查看到 hello-world 已经下载到本地

我们可以通过docker ps 或者 docker container ls 显示正在运行的容器,我们可以看到, hello-world 在输出提示信息以后就会停止运行,容器自动终止,所以我们在查看的时候没有发现有容器在运行。

我们从上面可以看出, docker 的功能是十分强大的,除此之外,我们还可以拉去一些 Ubuntu , Apache等镜像

八、Docker常用命令

8.1 镜像操作

操作 命令 说明
查找 docker search 关键字 可以在docker hub网站查看镜像详情
抽取 docker pull
docker pull mysql
docker pull mysql:5.7
:版本号,如果不指定,默认是latest
列表 docker images 查看本地所有的镜像
获取元信息 docker inspect 镜像ID 获取镜像元信息
删除 docker rmi -f 镜像id或镜像名:版本号 删除本地镜像,-f表示强制删除

8.2 容器操作

操作 命令 说明
运行 docker run – name 容器名 -p 宿主机端口:容器端口 -d -v -it 镜像id或镜像名:版本号 –name指定容器名,如果不指定会自动命名
-i 以交互模式运行
–t 分配一个终端,即命令行,通常组合使用-t
–p 指定端口映射,将主机的端口映射到容器内的端口
–d表示后台运行,即以守护方式运行容器
–v 指定挂载主机目录到容器目录
容器的列表 docker ps
docker rm -f $(docker ps -a -q)
把所有的容器都删除的命令
默认查看所有运行的容器(不包括已经关闭的)
-a表示显示所有的容器(包括已经关闭的)
-q只显示容器id号
启动容器 docker start 容器id或者容器名称 启动容器
关闭容器 docker start 容器id或者容器名称 关闭容器
日志 docker logs 容器id或者容器名称 获取容器日志
进入容器 docker exec -it 容器id或容器名称 /bin/bash 进入正在运行的容器并开启一个交互模式的终端,可以在容器中执行操作
拷贝文件 docker cp 主机中的文件路径 容器ID或容器名称:容器路径
docker cp 容器ID或容器名称:容器路径 主机中的文件路径
将宿主机中的文件拷贝到容器中;
将容器中的文件拷贝到宿主机中;
挂载文件(防止数据丢失) docker run --name mytomcat5 -p 8893:8080 -v /my/tomcat/data:/usr/local/tomcat/data -d tomcat 多个-v可以挂载多个
获取容器元信息 docker inspect 容器ID 获取容器的元信息

以centos为例
docker search centos
docker pull centos
docker run --name mycentos1 -it centos # 更改centos:latest创建容器,并以交互模式进入容器中
#实际上是在docker容器中运行了一个最精简版本的centos系统
exit
docker ps -a
docker start mycentos1
docker stop mycentos1
docker rm mycentos1

以tomcat为例
安装tomcat并进行端口映射
端口映射
8080端口映射为8888端口。

docker search tomcat
docker pull tomcat
docker run --name mytomcat1 -p 8888:8080 -d tomcat
精简版Tomcat  压缩到webapps.dist
将webapps.dist里的内容全部移到 /usr/local/tomcat/webapps
访问:192.168.1.137:8888
docker exec -it c0bcf6ea33 /bin/bash 进入到容器
mv /usr/local/tomcat/webapps/webapps.dist/*/usr/local/tomcat/webapps
exit  退出容器
#测试:http://宿主机地址:8888

挂载和拷贝(容器和宿主机通信)
拷贝:
运行:docker run --name mytomcat3 -8889:8080 -d tomcat
docker cp index.jsp 容器ID:容器路径 同理这两个对象可以调换
验证检查:docker exec -it 容器ID /bin/bash
exit
echo welcome to hundsun > index.jsp
docker cp index.jsp 容器id:/usr/local/tomcat/webapps/ROOT 将宿主机中的文件拷贝到容器指定的目录中

挂载:
运行:docker run --name mytomcat5 \
-p 8893:8080
-v /my/tomcat/data:/usr/local/tomcat/data
-d tomcat
通过-v参数,冒号前为宿主机目录,必须为绝对路径,冒号后为镜像内挂载的路径。默认挂载的路径权限为读写。如果指定为只读可以用:ro   -v /my/tomcat/data:/usr/local/tomcat/data:ro

docker run :根据镜像创建一个容器并运行一个命令,操作的对象是 镜像;
docker exec :在运行的容器中执行命令,操作的对象是 容器。

docker -h 去查看命令的详细的帮助文档docker update --restart=always redis # 设置镜像容器自启动
docker rmi 镜像名/镜像ID
docker restart [-i]  容器名/容器ID ## 重启容器
docker stop 容器名/容器ID (发送信号,等待停止)## 停止容器
docker kill 容器名/容器ID(直接停止)## 立即停止容器拉取一个 docker 镜像
docker pull image_name
// image_name 为镜像的名称,而如果我们想从 Docker Hub 上去下载某个镜像,我们可以使用以下命令:
docker pull centos:latest
// centos:lastest 是镜像的名称, Docker daemon 发现本地没有我们需要的镜像,会自动去 Docker Hub 上去下载镜像,下载完成后,该镜像被默认保存到 /var/lib/docker 目录下。查看镜像
docker images [OPTSIONS] [REPOSITORY]
docker images 查看下主机下存在多少镜像
-a  --all=false  显示所有镜像,默认并不显示中间层的镜像
-f  --filter=[]  显示时的过滤条件
--no-trunc=false   指定不使用截断的形式来显示数据,默认情况下我们用images查到的列表会截断镜像的唯一id
-q  --quiet=false  只显示镜像的唯一id删除镜像
docker rmi [OPTIONS] IMAGE [IMAGE...]
-f,--force=false 强制删除镜像
--no-prune=false 保留被删除镜像中被打标签的父镜像查看容器
docker ps -a    -a 是查看当前所有的容器,包括未运行的启动容器
docker run IMAGE [COMMAND]  [ARG...]
# IMAGE 是指启动容器所使用的操作系统镜像
# [COMMAND] [ARG...] 指的是容器启动后运行的命令及其参数启动交互容器式
#启动交互式容器
docker run -i -t IMAGE /bin/bash#退出交互式容器的bash,这样容器就会在后台运行
Ctrl+P+Q在run命令中增加了两个参数 -i -t ,并在容器启动时运行bash命令i --interactive=true | fasle 默认是false
用来告诉docker守护进程为容器始终打开标准输入
-t --tty = true | false 默认是false
告诉docker要为创建的容器分配一个--tty终端,这样新创建的容器才能提供一个交互式的shell启动守护式容器
docker run -d 镜像名 [COMMAND] [ARG...]
# -d 是指以后台的形式运行命令查看运行的容器
docker ps [-a] [-l]
[-a] 列出所有创建的容器
[-l] 列出最新创建的容器查看容器详细配置
docker inspect CONTAINER_ID删除停止的容器
docker rm 容器名/容器ID
-f : 通过SIGKILL信号强制删除一个运行中的容器
-v : 删除与容器关联的卷查看容器日志
docker logs [-f] [-t] [--tail] 容器名
-f  --follows=true | false 默认为false,告诉logs命令一直跟踪日志的变化并返回结果
-t  --timestamps=true | false 默认为false,在返回的结果上加上时间戳
--tail  = "all"   是选择返回结尾处多少数量的日志,如果不指定的话就返回所有的日志查看容器内进程
docker top 容器名/容器ID在运行容器进程内启动新进程
docker exec [-d] [-i] [-t]  容器名 [COMMAND] [ARG...]
eg :
docker exec -i -t 容器名 /bin/bash获取容器、镜像元数据
docker  inspect [OPTIONS] CONTAINER|IMAGE[CONTAINER|IMAGE...]——————————————————————————————————————————————————————————————————————————————我们该如何去对一个容器进行启动,重启和停止呢?我们可以用如下命令:
docker start container_name/container_id
docker restart container_name/container_id
docker stop container_name/container_id这个时候我们如果想进入到这个容器中,我们可以使用 attach 命令:
docker attach container_name/container_id那如果我们想运行这个容器中的镜像的话,并且调用镜像里面的 bash ,我们可以使用如下命令:
docker run -t -i container_name/container_id /bin/bash那如果这个时候,我们想删除指定镜像的话,由于 image 被某个 container 引用(拿来运行),如果不将这个引用的 container 销毁(删除),那 image 肯定是不能被删除。我们首先得先去停止这个容器:
docker ps
docker stop container_name/container_id然后我们用如下命令去删除这个容器:
docker rm container_name/container_id然后这个时候我们再去删除这个镜像:
docker rmi image_name补充:run centos,直接就退出,根本原因:docker跑centos,但没下发任何命令,所以跑起来后会自己退出。   因此要选择一个合适的命令 让容器保持前端运行。
❤ 注意:镜像的第一个启动程序必须是前台运行的(就是不退出的,控制台没法继续输入那种)

更多命令可以参考:https://www.runoob.com/docker/docker-command-manual.html

Docker 提供了一套简单实用的命令来创建和更新镜像,我们可以通过网络直接下载一个已经创建好了的应用镜像,并通过 Docker RUN 命令就可以直接使用。当镜像通过 RUN 命令运行成功后,这个运行的镜像就是一个 Docker 容器啦,容器可以理解为一个轻量级的沙箱, Docker 利用容器来运行和隔离应用,容器是可以被启动、停止、删除的,这并不会影响 Docker 镜像。


Docker 客户端是 Docker 用户与 Docker 交互的主要方式。当您使用 docker 命令行运行命令时, Docker 客户端将这些命令发送给服务器端,服务端将执行这些命令。 docker 命令使用 docker API 。 Docker 客户端可以与多个服务端进行通信。

我们将剖析一下 Docker 容器是如何工作的,学习好Docker容器工作的原理,我们就可以自己去管理我们的容器了。

九、Docker架构

Docker 使用的是 C/S 结构,即客户端/服务器体系结构。明白了Docker 客户端与 Docker 服务器进行交互时, Docker 服务端负责构建、运行和分发 Docker 镜像。 也知道了Docker 客户端和服务端可以运行在一台机器上,可以通过 RESTful 、 stock 或网络接口与远程 Docker 服务端进行通信。


Docker 的核心组件包括:

  1. Docker Client
  2. Docker daemon
  3. Docker Image
  4. Docker Registry
  5. Docker Container

Docker 采用的是 Client/Server 架构。客户端向服务器发送请求,服务器负责构建、运行和分发容器。客户端和服务器可以运行在同一个 Host 上,客户端也可以通过 socket 或 REST API 与远程的服务器通信。

Docker Client
Docker Client ,也称 Docker 客户端。它其实就是 Docker 提供命令行界面 (CLI) 工具,是许多 Docker 用户与 Docker 进行交互的主要方式。客户端可以构建,运行和停止应用程序,还可以远程与Docker_Host进行交互。最常用的 Docker 客户端就是 docker 命令,我们可以通过 docker 命令很方便地在 host 上构建和运行 docker 容器。

Docker daemon
Docker daemon 是服务器组件,以 Linux 后台服务的方式运行,是 Docker 最核心的后台进程,我们也把它称为守护进程。它负责响应来自 Docker Client 的请求,然后将这些请求翻译成系统调用完成容器管理操作。该进程会在后台启动一个 API Server ,负责接收由 Docker Client 发送的请求,接收到的请求将通过Docker daemon 内部的一个路由分发调度,由具体的函数来执行请求。

默认配置下, Docker daemon 只能响应来自本地 Host 的客户端请求。如果要允许远程客户端请求,需要在配置文件中打开 TCP 监听。我们可以照着如下步骤进行配置:

1、编辑配置文件 /etc/systemd/system/multi-user.target.wants/docker.service ,在环境变量 ExecStart 后面添加 -H tcp://0.0.0.0,允许来自任意 IP 的客户端连接。

2、重启 Docker daemon
systemctl daemon-reload
systemctl restart docker.service

3、我们通过以下命令即可实现与远程服务器通信
docker -H 服务器IP地址 info
-H 是用来指定服务器主机, info 子命令用于查看 Docker 服务器的信息

Docker Image
Docker 镜像可以看作是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。我们可将 Docker 镜像看成只读模板,通过它可以创建 Docker 容器。

镜像有多种生成方法:
1.从无到有开始创建镜像
2.下载并使用别人创建好的现成的镜像
3.在现有镜像上创建新的镜像

我们可以将镜像的内容和创建步骤描述在一个文本文件中,这个文件被称作 Dockerfile ,通过执行 docker build 命令可以构建出 Docker 镜像

Docker Registry
Docker registry 是存储 docker image 的仓库,它在 docker 生态环境中的位置如下图所示:

运行docker push、docker pull、docker search时,实际上是通过 docker daemon 与 docker registry 通信。

Docker Container
Docker 容器就是 Docker 镜像的运行实例,是真正运行项目程序、消耗系统资源、提供服务的地方。 Docker Container 提供了系统硬件环境,我们可以使用 Docker Images 这些制作好的系统盘,再加上我们所编写好的项目代码, run 一下就可以提供服务啦。

Docker镜分层结构


  一个tomcat为什么那么大?采用了分层结构,一层一层堆叠起来,但是从外面来说,只能看到最外层的文件系统(镜像层),本身包括了linux内核系统,jdk等。
  镜像是一个轻量级,可以执行的独立软件包。用来打包软件运行的环境和基于运行环境的软件,包含了运行某个软件所需要的所有内容
  分层结构:共享资源,便于复用(许多镜像都是从相同的基础镜像构建而来的,基础镜像只需保存一份)

Docker镜像加载原理

UnionFs:联合文件系统
UnionFs(联合文件系统):Union文件系统(UnionFs)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下,UnionFs联合文件系统是Docker镜像的基础,镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录

Docker镜像加载原理
Docker的镜像实际上由一层一层的UnionFs文件系统组成bootfs:主要包含 bootloader和 Kernel,bootloader主要是引导加 kernel,Linux刚启动时会加bootfs文件系统,在 Docker镜像的最底层是bootfs,这一层与我们典型的Linux/Unix系统是一样的,包含bootfs加载器和内核,当bootfs加载完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs转交给内核,此时系统也会卸载bootfs。

rootfs:在 bootfs之上,包含的就是典型 Linux系统中的/dev、/proc、/bin、/etc等标准目录和文件,rootfs就是各种不同的操作系统发行版,比如:Ubuntu,、CentOS等等

简单理解:

  1. 对于Docker安装OS来说:就是Docker使用了Linux本身的bootfs,只需要安装自己所需的rootfs。

  2. 对于Docker安装普通镜像来说:就是Docker本身是分层下载镜像,所以可以提取出公共层镜像,进行复用。

十、创建镜像

镜像是只读的,不能修改,但是镜像生成的容器可以修改。那如何更新镜像?

两种方式:
更新镜像:docker commit命令
构建镜像:使用docker build命令,需要创建dockerfile文件

10.1 更新镜像

从容器创建一个新的镜像。即先使用基础镜像创建一个容器,然后对容器进行修改,最后使用commit命令提交为一个新的镜像
步骤:
docker commit -m = “更新镜像拉” -a=”guozige” 已有的容器id 新的镜像名
docker commit -a="test" -m="test" 容器id tomcat01:1.0
将已有的容器id 保存为新的镜像,并添加提交人信息和说明信息。

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
OPTIONS说明:

-a :提交的镜像作者;
-c :使用Dockerfile指令来创建镜像;
-m :提交时的说明文字;
-p :在commit时,将容器暂停。

10.2 构建镜像

docker build -f Dockerfile文件的路径 -t 镜像名:tag 命令执行的上下文

通过Dockerfile重新构建一个镜像
docker build -f Dockerfile -t tomcat:v2 . (这个点就是上下文)

使用当前目录的 Dockerfile 创建镜像,标签为 runoob/ubuntu:v1。
docker build -t runoob/ubuntu:v1 .

也可以通过 -f Dockerfile 文件的位置:
$ docker build -f /path/to/a/Dockerfile .

利用新构建的镜像再去创建容器
docker run --name mytomcat2 -p 8888:8080 tomcat:v2

理解构建上下文
当你触发docker build命令时,当前目录就被称为构建上下文(build context)。默认情况下 Dockerfile文件就在这个目录下(直接用 docker build -t hello:v1 .),但是可以通过 -f 参数来指定Dockerfile的位置。不管Dockerfile在哪里,当前目录中的所有文件和目录都会作为构建上下文发送到docker daemon 进程。

十一、Dockerfile

11.1 简介

  • Dockerfile 是自动构建 docker 镜像的配置文件, 用户可以使用 Dockerfile 快速创建自定义的镜像。Dockerfile 中的命令非常类似于 linux 下的 shell 命令,由一系列命令和参数脚本构成。
  • Dockerfile是从FROM命令开始,紧接各种命令和参数,最终会生成一个新的镜像。
  • Dockerfile 是镜像和容器的关键,并且 Dockerfile 还可以很轻易的去定义镜像内容

通过下面这幅图来直观地感受下 Docker 镜像、容器和 Dockerfile 三者之间的关系。
我们从上图中可以看到, Dockerfile 可以自定义镜像,通过 Docker 命令去运行镜像,从而达到启动容器的目的。

Dockerfile 是由一行行命令语句组成,并且支持已 # 开头的注释行。
如下:
FROM debian
RUN apt-get install emocs
RUM apt-get install apache2
CMD [“/bin/bash”]
①新镜像从Debian base镜像上构建
②安装emocs编辑器
③安装apache2
④容器启动时运行bash

一般来说,我们可以将 Dockerfile 分为四个部分:

  • 基础镜像(父镜像)信息指令 FROM
  • 维护者信息指令 MAINTAINER
  • 镜像操作指令 RUN 、 EVN 、 ADD 和 WORKDIR 等
  • 容器启动指令 CMD 、 ENTRYPOINT 和 USER 等

步骤
编写dockerfile文件
使用docker build 构建镜像
使用docker run 运行容器

11.2 语法规则

  • 指令必须要大写,且后面必须要跟参数
  • 第一条指令必须是FROM,指定基础镜像(仓库中的)
  • 指令按照从上往下的顺序,依次执行,逐层构建
    Centos7构建的规则

11.3 常用的指令

指令 解释
FROM 指定基础镜像,即当前镜像是基于哪个镜像
ADD 将构建的主机的文件复制到镜像(镜像源可以是文件、目录、归档文件或远程URL)
COPY 拷贝文件/目录到镜像中。类似于ADD,不过仅用于文件和目录。
CMD 设置在容器中执行的默认命令
MAINTAINER 指定作者
RUN 指定构建过程中的要运行的命令
ENV 设置环境变量
WORKDIR 指定默认的工作目录,即进入容器后默认的目录
VOLUME 创建挂载点,用于共享和持久化
ENTRYPOINT 指定容器要运行的命令,与CMD有区别
USER 设置运行容器和后续构建指令要使用的账户名
EXPOSE 指定对外暴露的端口
DockerFile
DockerFile是用来构建Docker镜像的文件(命令参数脚本)DockerFile构建指令
FROM                # 基础镜像,一切从这里开始构建
MAINTAINER             # 镜像是谁写的, 姓名+邮箱
RUN                    # 镜像构建的时候需要运行的命令
ADD                    # 步骤,tomcat镜像,这个tomcat压缩包!添加内容 添加同目录
WORKDIR                # 镜像的工作目录
VOLUME                # 挂载的目录
EXPOSE                # 保留端口配置
CMD                    # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT            # 指定这个容器启动的时候要运行的命令,可以追加命令
COPY                # 类似ADD,将我们文件拷贝到镜像中
ENV                    # 构建的时候设置环境变量!





应用解耦:保证我们的容器功能明确和模块化,如果容器之间相互依赖(容器之间可能需要通信),可以使用Docker container networks确保容器通信。

因此减小镜像层数对于镜像构建非常重要,传言镜像的层数有一百二十七层限制。 把RUN命令压缩,用&&连接

如:
RUN tar zxvf apache.tar.gz
&& cp -R apache /usr/local/bin
&& export PATH=/usr/local/bin/apache

11.4 自定义centos

#vi Dockerfile
FROM centos   #指定基础镜像
MAINTAINER guozige  #指定作者
ENV MYPATH /homt/test  #设置环境变量
RUN mkdir -p /home/test  #创建工作路径,镜像创建过程当中会自动执行的命令
WORKDIR $MYPATH  #指定进入容器后的目录
RUN yum -y install vim
RUN yum -y install wget
RUN yum -y install ll
RUM yum -y install passwd openssh-server;yum clean all  #下载ssh
RUN echo “123456” | passwd --stdin root  #修改root密码
EXPOSE 22  #开启22端口
VOLUME [“/date1”,”/date2”]
CMD [“/bin/bash”]  #表示容器运行后,自动会启动,和RUN不一样。
CMD [“/usr/sbin/sshd -D”]  #启动ssh#docker build -f Dockerfile -t guozige/mycentos:v1 .   -t是为新镜像设置仓库和名称,其中 guozige 为仓库名, mycentos:v1为镜像名
docker imagesdocker run --name mycentos22 -it -d -p 8080:22 --privileged=true guozige/mycentos:v1/sbin/init
创建容器,并且映射了 8080 端口,这样我们可以用浏览器去访问这个:http://localhost:8080/ 或者 http://本机的IP地址:8080/,页面返回信息:
docker ps -a

11.5 创建Tomcat镜像

1.准备镜像文件:Tomcat和JDK的压缩包

2.编写DockerFile

FROM centos
MAINTAINER fortuneteller<1746344046@qq.com>COPY README.txt /usr/local/README.txtADD jdk-8u251-linux-x64.tar.gz /usr/local
ADD apache-tomcat-9.0.35.tar.gz /usr/localRUN yum -y install vimENV MYPATH /usr/local
WORKDIR $MYPATHENV JAVA_HOME /usr/local/jdk1.8.0_251
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.35
ENV CATALINA_BASH /usr/local/apache-toacat-9.0.35
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/binEXPOSE 8080CMD ["/usr/local/apache-tomcat-9.0.35/bin/catalina.sh", "run"]

3.打包镜像

# 这里使用的是Dockerfile来明白的脚本,所以省略-f
docker build -t mytomcat .

4.启动镜像

docker run -d -p 3344:8080 --name mttomcat -v /home/fortuneteller/tomcat/test:/

十二、将本地的镜像发布到阿里云

阿里云——容器镜像服务快速入门
Docker 镜像基本操作

操作地址:cr.console.aliyun.com/repository

1.登录阿里云的开发者平台,创建命名空间和镜像仓库
命名空间:guozige
仓库名称:mycentos
docker login --username=gg registry.cn-hangzhou.aliyuncs.com

2.创建指定镜像的tag,归入某个仓库(镜像名字和仓库命名空间要对应的)
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/guozige/mycentos:[镜像版本号]
3.将镜像推送push到仓库Registry中
docker push registry.cn-hangzhou.aliyuncs.com/guozige/mycentos:[镜像版本号]

从仓库拉取镜像
docker pull registry.cn-hangzhou.aliyuncs.com/guozige/mycentos:[镜像版本号]

十三、网络操作

13.1 Namespace

  • Linux Namespace是Kernel的一个功能,它可以隔离一系列系统的资源,比如PID(ProcessID),User ID,Network等等。
  • Linux Namespace将内核的全局资源做封装,使得每个Namespace都有一份独立的资源,因此不同的进程在各自的Namespace内对同一种资源的使用不会相互干扰。

docker容器主要通过资源隔离来实现的,应该具有的6种资源隔
namespace 的六项隔离

类型 隔离的内容 系统调用参数
MOUNT 挂载点 CLONE_NEWNS
UTS 主机名域名 CLONE_NEWUTS
IPC 信号量、消息队列与共享内存 CLONE_NEWIPC
PID 进程编号 CLONE_NEWPID
Network 网络设备、网络栈、端口等 CLONE_NEWNET
USER 用户与组 CLONE_NEWUSER

Namespace的API主要使用三个系统调用

  • clone 创建新的命名空间,相当于创建容器 —— 新建
  • unshare 对进程的处理,将某个进程移出 —— 移除再新建
  • setns 将进程加入某个已存在的Namespace —— 加入到老的容器


这里只是大概说下

13.2 网络模式

Docker的5种容器网络模式:
①none:不配置任何网络功能。
②container:共享另一个运行中的容器Network Namespace,共享相同的网络视图。
③host:共享主机Root Network Namespace,容器有完整的权限可以操纵主机的协议栈、路由表和防火墙等,所以被认为是不安全的(不推荐)
④bridge:Docker设计的NAT网络模型。
⑤overlay:Docker原生的跨主机多子网模型。(不同的主机不同的网段,把众多主机结合成一个子网)

None模式

使用 none 模式,Docker 容器拥有自己的 Network Namespace,但是,并不为 Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。

这种网络模式下容器只有 lo 回环网络,没有其他网卡。none 模式可以在容器创建时通过–network none 来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

应用场景

  • 启动一个容器处理数据,比如转换数据格式
  • 一些后台的计算和处理任务

none模式下,需要–net=none参数启动容器:
#docker run --net=none --name None -it centos:latest ip addr show
解释:启动一个没有网络模式的容器,以-it运行,使用centos最新版镜像。ip addr show是命令

另外一种方式,是进去之后再ip addr show

Container模式

这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

container模式下,需要–net=container:$CONTAINERID参数启动容器:
首先以默认网络配置(bridge模式)启动一个容器,设置主机名为Bridge,dns为8.8.4.4。
docker run -h dockerNet --dns 8.8.4.4 --name Bridge -it centos:latest /bin/bash
解释:-h就是-hostname

如果使用container模式,就要–net=container打通两个容器网络,两个容器要处于运行状态
在container模式下,需要–net=container:$CONTAINER_ID参数启动容器
命令:以container模式(–net=container:1742a415e890)启动一个容器。
docker start 1742a415e890
docker run --net=container:1742a415e890 --name Container -it centos:latest /bin/bash
这里是利用上面创建的容器Bridge做container的试验
可以发现容器的信息跟桥接效果一样的,IP地址,DNS,主机是继承了前一个命令创建的Bridge信息

#docker ps 不加任何参数,可以看到运行中的docker
#docker exec -it Bridge /bin/bash 进入到Bridge查看网络信息

Host模式

host模式启动容器时需要指定–net=host参数:
docker run --net=host --name Host -it centos:latest /bin/bash

注意:Host模式下容器可以操纵主机的网络配置,它会继承主机的所有网络信息,并且访问外面真机也是通的,其他模式的话要通过端口映射才行,处于安全考虑,尽可能避免使用host模式

如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

使用 host 模式的容器可以直接使用宿主机的 IP 地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行 NAT,host 最大的优势就是网络性能比较好,但是 docker host 上已经使用的端口就不能再用了,网络的隔离性不好。

Bridge模式

Docker daemon启动时会在主机创建一个Linux网桥(默认docker0)

  • 创建容器的时候会创建一个eth0,eth0和veth*是成对的。
  • docker会将一端挂在docker0网桥上,另一端放在容器的network namespace。

当 Docker 进程启动时,会在主机上创建一个名为 docker0 的虚拟网桥,此主机上启动的 Docker 容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。

从 docker0 子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的默认网关。在主机上创建一对虚拟网卡 veth pair 设备,Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为 eth0(容器的网卡),另一端放在主机中,以 vethxxx 这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中。可以通过 brctl show 命令查看。

bridge 模式是 docker 的默认网络模式,不写–network 参数,就是 bridge 模式。使用 docker run -p 时,docker 实际是在 iptables 做了 DNAT 规则,实现端口转发功能。可以使用 iptables -t nat -vnL 查看。

1.创建docker0网桥
2.新建docker0网桥的子网及路由
3.创建iptables规则

查看主机网桥信息
#brctl show查看docker0网卡信息
[root@aliyun ~]# ip addr show docker0
5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:81:2d:37:c6 brd ff:ff:ff:ff:ff:ffinet 172.17.0.1/16 scope global docker0valid_lft forever preferred_lft forever

默认docker0分配了172.17.0.1/16的子网,容器以bridge网络模式运行时默认从这个子网分配IP。

查看内核IP路由表
#route -n

以下进行Bridge模式测试,为了试验它的缺点
#docker run -itd --name con1 centos /bin/bash
#docker run -itd --name con2 centos /bin/bash

#docker exec -it con1 /bin/bash
#docker exec -it con2 /bin/bash

#docker stop con2
#docker stop con1
#docker start con2 先启动con2
#docker start con1 再启动con1
#docker exec -it con2 /bin/bash
#docker exec -it con1 /bin/bash
查看会发现IP地址就换过来了,因此容器用Bridge启停顺序要一样才行,不然IP地址会变换

13.3 端口映射

通过-P或-p参数来指定端口映射

  • 使用-P标记时,Docker会随机映射一个49000-49900的端口至容器内部开放的网络端口
    #docker run --name Port -itd -P centos:latest /bin/bash
    #docker ps-1

  • 使用-p标记时,可以指定要映射的端口,一个指定端口上只可以绑定一个容器。
    支持的格式有

    ip:ip:hostPort:containerPort
    ip:containerPort
    hostPort:containerPort#docker [root@aliyun ~]# docker run -it --name con3 -p 22800:22 centos /bin/bash
    [root@6b69298a148b /]# service sshd start
    [root@aliyun ~]# docker port con3 可以获得端口
    

然后通过Xshell语句,连接22800暴露的端口,

13.4 容器互联

容器互联实现容器间通信

  • 自定义容器命名,使用–name标记可以为容器自定义命名
    容器的连接系统除了端口映射外,还有另一种可以与容器中应用进行交互的方式。 它会在源和接收容器之间创建一个隧道,接收容器可以看到源容器指定的信息。连接系统依据容器的名称来执行。因此,首先需要自定义一个好记的容器命名。

  • 容器互联
    使用–link参数可以让容器之间安全的进行交互
    –link参数的格式为–link name:othername
    name是要链接的容器的名称
    othername是这个连接的别名

这里的Bridge是之前创建好的容器
[root@aliyun ~]# docker run -itd -P --name Link --link Bridge:Link centos:latest /bin/bash
89c7492bd466d1493ce41dd4b8d5d26db6a2b75315c9bb6287600536464ab3ba

[root@aliyun ~]# docker exec -it Link /bin/bash
[root@89c7492bd466 /]# cat /etc/hosts 自动写入

13.5 网络支持

Weave、Flannel

十四、仓库与数据管理

仓库(Repository)是集中存放镜像的地方,分公共仓库和私有仓库。

1.共有仓库

保存和分发镜像最直接的方法 —— Docker Hub

仓库操作步骤:
①注册Docker Hub账号(user)
http://hub.docker.com/
②登录Docker Host (先启动docker服务)
docker login -u user -p password

③修改镜像的Repository 与 Docker Hub账号匹配,名字要一样
docker tag centos guozige/centos:v1

  • docker tag : 标记本地镜像,将其归入某一仓库。创建一个镜像,在tag centos的基础上(同样ID,同样大小,名字不同), 名字:guozige/centos:v1

④镜像上传到Docker Hub
docker push guozige/centos:v1
docker push guozige/centos:v1

⑤dockerhub的公共仓库查看上传的镜像

⑥去别的机器(不存在这个镜像名的)拉取公共仓库镜像
docker pull guozige/centos:v1

⑦docker search centos 从registry仓库搜索镜像

公共仓库不足:

  • 需要internet连接,而且下载和上传速度慢
  • 上传到Docker Hub的镜像任何人都能访问,私有repository收费
  • 安全原因很多组织不允许将镜像放到外网

最佳解决方案:搭建私有仓库

2.私有仓库

Docker 官方提供了一个搭建私有仓库的镜像 registry ,只需把镜像下载下来,运行容器并暴露5000端口,就可以使用了。
①自动下载并启动一个registry容器,创建本地的私有仓库服务
docker pull registry:2
将上传的镜像放到/opt/registry目录,本地监听端口为5000
docker run -d -p 5000:5000 --name Registry -v /opt/registry:/tmp/registry registry:2
通过-v参数,冒号前为宿主机目录,必须为绝对路径,冒号后为镜像内挂载的路径。

Registry服务默认会将上传的镜像保存在容器的/tmp/registry,我们将主机的/opt/registry目录挂载到该目录,即可实现将镜像保存到主机的/opt/registry目录了。

提示:成功安装docker registry,在浏览器中输入http://127.0.0.1:5000/v2 成功返回json数据

注意:默认情况下,会将仓库存放于容器内的/tmp/registry目录下,这样如果容器被删除,则存放于容器中的镜像也会丢失,所以我们一般情况下会指定本地一个目录挂载到容器内/tmp/registry下

②修改镜像的Repository与Registry匹配
docker tag : 标记本地镜像,将其归入某一仓库。
语法:docker tag IMAGEETAG][REGISTRYHOST/[USERNAME/INAME[:TAG]
#docker tag centos 127.0.0.1:5000/centos

③镜像上传到私有仓库
#docker push 127.0.0.1:5000/centos

④查看仓库中的镜像
用curl方式
#curl http://127.0.0.1:5000/v2/search

用catalog方式
访问 http://127.0.0.1:5000/v2/_catalog 查看私有仓库目录,可以看到刚上传的镜像了:

⑤下载私有仓库的镜像
使用如下命令:
docker pull localhost:5000/镜像名:版本号
例如
docker pull localhost:5000/centos

私有仓库搭建环节

私有仓库异常处理
原因分析
因为Docker从1.3.X之后,与docker registry交互默认使用的是https,然而此处搭建的私有仓库只提供http服务,所以当与私有仓库交互时就会报上面的错误。
为了解决这个问题需要在启动docker server时启动参数为默认使用http访问。

解决方案
在“/etc/docker”目录下,创建“daemon.json”文件。在文件中写入:“insecure-registries”:[“127.0.0.1:5000”],保存退出后,重启docker
[root@aliyun ~]# cat /etc/docker/daemon.json
{
“registry-mirrors”: [“https://xxx(自己的阿里云)gglie.mirror.aliyuncs.com”]
“insecure-registries”:[“127.0.0.1:5000”]
}

我用上面的方法没用,百度找到答案了
https://www.cnblogs.com/programmer-tlh/p/10996443.html 第一个改了后正常
但是改了之后docker重启失败,用这个修复好,正常确定后 再次修改
https://blog.csdn.net/li1325169021/article/details/90782846

在十五、会介绍harbor
docker 官方提供的私有仓库 registry,用起来虽然简单 ,但在管理的功能上存在不足。 Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器
https://www.cnblogs.com/huanchupkblog/p/10843800.html

3.数据存储(共享)

在Docker的使用过程中往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,所以这就涉及到Docker容器的数据操作。
容器中数据管理主要有两种方式:数据卷和数据卷容器。

数据卷(Data Volumes) 容器内数据直接映射到本地宿主机。
数据卷容器(Data Volume Containers) 使用特定容器维护数据卷。

数据卷

数据卷(Data Volumes) 容器内数据直接映射到本地宿主机。

镜像程序运行时通过"-v /主机目录文件名:/容器目录名" 命令,将容器卷指定一个主机目录,这样我们的程序运行的数据就可以持久保存到这个映射的主机目录文件当中。

数据卷本质上是Docker Host文件系统中的目录或文件,能够直接被挂载到容器的文件系统中,
-v 的格式为<host path>:<container path>
数据卷的使用,类似于Linux下对目录或文件进行mount操作。

数据卷的特点

  • 数据卷是目录或文件
  • 容器可读写卷中的数据
  • 数据可以被永远的保存,即使使用它的容器已经销毁

命令创建数据卷
docker run -it -v hostDirectory主机目录:containerDirectory容器内目录 imageName /bin/bash

加权限,容器内只读
docker run -it -v hostDirectory:containerDirectory:ro imageName /bin/bash

DockerFile创建数据卷(centos为例)

1.在指定文件夹下创建Dockerfile文件:vim Dockerfile
2.编辑Dockerfile
#volume test
FROM centos
VOLUME ["/container/dataVolume1","/container/dataVolume2"]
CMD echo "finished,-------------successful"
CMD /bin/bash
3.将Dockerfile构建为docker镜像:docker -f build Dockerfile -t imageName .    (说明:. 用于路径参数传递,标识当前路径)

实例:挂载MySQL数据库到Liunx宿主机

  1. 下载MySQL
    docker pull mysql
  2. 启动并挂载 -e:特别注意需要设置密码
    docker run -d -p 3344:3306 -v /home/conf:/etc/mysql/conf.d -v /home/logs:/logs
  3. 使用远程连接软件会报错
# 解决报错
# 1. 进入容器内
docker exec -it 容器ID /bin/bash
# 2. 进入MySQL
mysql -uroot -p123456
# 3. 授权
mysql> GRANT ALL ON *.* TO 'root'@'%';
# 4. 刷新权限:
mysql> flush privileges;
# 5. 更新加密规则:
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER;
# 6. 更新root用户密码:
mysql> ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
# 7. 刷新权限:
mysql> flush privileges;

具名和匿名挂载

-v 容器内路径          # 匿名挂载
-v 卷名:容器内路径         # 具名挂载
-v 宿主机路径:容器内路径 # 指定路径挂载
Docker容器内的卷,在没有指定目录的情况下都在/var/lib/docker/volumes/xxx/_data下

拓展:绑定权限

通过 -v 容器内路径:ro rw 改变读写权限
ro # readonly 只读
rw # readwrite 可读可写
docker run -d nginx01 -v nginxdemo:/etc/nginx:ro nginx
docker run -d nginx01 -v nginxdemo:/etc/nginx:rw nginx
ro:只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作

数据卷容器

如我我们经常需要多个容器之间进行数据共享我们需要用到命令“–volumes-from”
具体实例:
1)我们从仓库拉一个centos的容器镜像
$ docker pull centos

2)然后运行这个镜像并创建一个数据卷容器mycentos,并在其中创建一个数据卷挂载到/mydata
$ docker run -it -v /mydata --name mycentos centos

3)再运行两个容器,在这两个容器中使用–volumes-from来挂载mycentos容器中的数据卷.
$ docker run -it --volumes-from mycentos --name soncentos1 centos
$ docker run -it --volumes-from mycentos --name soncentos2 centos

此时,容器soncentos1和soncentos2都挂载同一个数据卷到相同的/mydata 目录。三个容器任何一方在该目录下的写入数据,其他容器都可以看到。

创建数据卷容器

1.启动dc01容器:docker run -it --name dc01 imageName
2.dc02继承自dc01:docker run -it --name dc02 --volumes-from dc01 imageName

容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止!!!

注:

  • 可以多次使用–volumes-from参数来从多个容器挂载多个数据卷。还可以从其他已经挂载了容器卷的容器来挂载数据卷。
  • 使用–volumes-from参数所挂载数据卷的容器自身并不需要保持在运行状态。
  • 如果删除了挂载的容器(包括dbdata、db1和db2),数据卷并不会被自动删除。如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时显式使用docker rm -v命令来指定同时删除关联的容器。

十五、网络与集群管理

1.Pipework原理解析

Pipework——一个帮助用户扩展Docker网络功能的工具。
Pipework号称是容器的SDN解决方案,可以在复杂场景下将容器连接起来

配置容器的IP地址和网关:
①下载pipework
$ git clone https://github.com/jpetazzo/pipework

②将pipework脚本放下$PATH环境变量所指定的目录下,如
/usr/local/bin/
$cp ~/pipework/pipework /usr/local/bin/

③完成容器的配置
$ pipework br0 uf20 192.168.1.137/24@192.168.1.137

docker网络,上面讲的那几种功能还不够强大。
比如,启动了多个容器,全部停止,不是按顺序启动的话,IP地址会错乱,互相占用,导致xml或sid无效。。为了解决这个问题,就有Pipework

配置命令执行的操作:
①查看主机中是否存在br0网桥,不存在就创建;
②向uf20中加入一块名为eth1的网卡,并配置lP地址为192.168.1.137/24;
③若uf20中已经有默认路由,则删掉,把192.168.1.137设置为默认路由的网关;
④将uf20容器连接到之前创建的网桥br0上。

2.Open vSwitch简介

Open vSwitch是一个开源的虚拟交换机。
相比于Linux Bridge,Open vSwitch支持VLAN、QoS等功能,同时还提供对OpenFlow协议的支持,可以很好地与SDN体系融合。因此,提供对Open vSwitch的支持,有助于借助OpenvSwitch的强大功能来扩展Docker网络。

安装Open vSwitch:
①安装依赖包

[root@aliyun ~]# yum -y install make gcc openssl-devel autoconf automake rpm-build redhat-rpm-config
[root@aliyun ~]# yum -y install python-devel openssl-devel kernel-devel kernel-debug-devel libtool wget selinux-policy-devel

②预处理

[root@aliyun ~]# cd ~
[root@aliyun ~]# mkdir -p ~/rpmbuild/SOURCES
[root@aliyun ~]# wget http://openvswitch.org/releases/openvswitch-2.7.2.tar.gz
[root@aliyun ~]# cp openvswitch-2.7.2.tar.gz ~/rpmbuild/SOURCES/
[root@aliyun SOURCES]# tar xfz openvswitch-2.7.2.tar.gz
[root@aliyun SOURCES]# sed 's/openvswitch-kmod, //g' openvswitch-2.7.2/rhel/openvswitch.spec > openvswitch-2.7.2/rhel/openvswitch_no_kmod.spec

③构建RPM包

[root@aliyun openvswitch-2.7.2]# rpmbuild -bb --nocheck ~/rpmbuild/SOURCES/openvswitch-2.7.2/rhel/openvswitch_no_kmod.spec

④安装
yum localinstall ~/rpmbuild/RPMS/x86_64/openvswitch-2.7.2-1.x86_64.rpm
⑤启动相关服务
systemctl start openvswitch.service

3.OVS划分VLAN

- 在计算机网络中,传统的交换机虽然能隔离冲突域,提高每一个端口的性能,但并不能隔离广播域,当网络中的机器足够多时会引发广播风暴。同时,不同部门、不同组织的机器连在同一个二层网络中也会造成安全问题。因此,在交换机中划分子网、隔离广播域的思路便形成了VLAN的概念。
  VLAN即虚拟局域网,按照功能、部门等因素将网络中的机器进行划分,使之分属与不同的部分,每一个部分形成一个虚拟的局域网络,共享一个单独的广播域。
  在多租户的云环境中,VLAN是一个最基本的隔离手段。

  • 单主机Docker容器的VLAN划分
    在Docker默认网络模式下,所有的容器都连在docker0网桥上。docker0网桥是普通的Linux网桥,不支持VLAN功能,为了方便操作,使用Open vSwitch代替docker0进行VLAN划分。

    ①创建容器
    docker run -itd --name con1 centos /bin/bash
    docker run -itd --name con2 centos /bin/bash
    docker run -itd --name con3 centos /bin/bash
    docker run -itd --name con4 centos /bin/bash

    ②划分VLAN
    pipework ovs0 con1 10.0.0.1/24 @100
    pipework ovs0 con2 10.0.0.2/24 @100
    pipework ovs0 con3 192.168.0.3/24 @200
    pipework ovs0 con4 192.168.0.4/24 @200
    未修改,未划分,现在是会根据启动顺序从小到大获取。
    划分vlan后
    pipework配置完成后,每个容器都多了一块eth1网卡,eth1连在ovs0网桥上,并且进行了VLAN的隔离。
    通过nc命令测试各容器之间的连通性时发现,con1和con2可以互相通信,但与con3和con4隔离。

ovs0 结合Open vSwitch,以ovs0去划分

测试验证:进入容器去ping
#docker exec -it con4 /bin/bash

4.Shipyard

Shipyard 是一个基于 Web 的 Docker 管理工具,支持多 host,可以把多个 Docker host 上的 containers 统一管理;可以查看 images,甚至 build images;并提供 RESTful API 等等。 Shipyard 要管理和控制 Docker host 的话需要先修改 Docker host 上的默认配置使其支持远程管理。


但这个已经暂停更新了

5.harbor

https://www.cnblogs.com/huanchupkblog/p/10843800.html

docker 官方提供的私有仓库 registry,用起来虽然简单 ,但在管理的功能上存在不足。 Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,harbor使用的是官方的docker registry(v2命名是distribution)服务去完成。harbor在docker distribution的基础上增加了一些安全、访问控制、管理的功能以满足企业对于镜像仓库的需求。

十六、自定义 docker0 桥的网络属性信息

自定义 docker0 桥的网络属性信息需要修改/etc/docker/daemon.json 配置文件

[root@localhost ~]# cd /etc/docker/
[root@localhost docker]# vim daemon.json
[root@localhost docker]# systemctl daemon-reload
[root@localhost docker]# systemctl restart docker
{"registry-mirrors": ["https://4hygggbu.mirror.aliyuncs.com/"],"bip": "192.168.1.5/24"
}
EOF[root@localhost ~]# vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375  -H unix:///var/run/docker.sock
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl restart docker

创建新网络

[root@localhost ~]# docker network create ljl -d bridge
883eda50812bb214c04986ca110dbbcb7600eba8b033f2084cd4d750b0436e12
[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
0c5f4f114c27   bridge    bridge    local
8c2d14f1fb82   host      host      local
883eda50812b   ljl       bridge    local
85ed12d38815   none      null      local

创建一个额外的自定义桥,区别于 docker0

[root@localhost ~]# docker network create -d bridge --subnet "192.168.2.0/24" --gateway "192.168.2.1" br0
af9ba80deb619de3167939ec5b6d6136a45dce90907695a5bc5ed4608d188b99
[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
af9ba80deb61   br0       bridge    local
0c5f4f114c27   bridge    bridge    local
8c2d14f1fb82   host      host      local
883eda50812b   ljl       bridge    local
85ed12d38815   none      null      local

使用新创建的自定义桥来创建容器:

[root@localhost ~]# docker run -it --name b1 --network br0 busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:C0:A8:02:02inet addr:192.168.2.2  Bcast:192.168.2.255  Mask:255.255.255.0UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:11 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0RX bytes:962 (962.0 B)  TX bytes:0 (0.0 B)

再创建一个容器,使用默认的 bridge 桥:

[root@localhost ~]# docker run --name b2 -it busybox
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:C0:A8:01:03inet addr:192.168.1.3  Bcast:192.168.1.255  Mask:255.255.255.0UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:6 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0RX bytes:516 (516.0 B)  TX bytes:0 (0.0 B)

Docker快速入门,看这个就够了相关推荐

  1. groovy if 判断字符串_Groovy快速入门看这篇就够了

    原标题:Groovy快速入门看这篇就够了 来自:刘望舒(微信号:liuwangshuAndroid) 前言 在前面我们学习了和两篇文章,对Gradle也有了大概的了解,这篇文章我们接着来学习Groov ...

  2. docker快速入门_Docker标签快速入门

    docker快速入门 by Shubheksha 通过Shubheksha Docker标签快速入门 (A quick introduction to Docker tags) If you've w ...

  3. Kubernetes CKA认证运维工程师笔记-Docker快速入门

    Kubernetes CKA认证运维工程师笔记-Docker快速入门 1. Docker 概念与安装 1.1 Docker 是什么 1.2 Docker 基本组成 1.3 版本与支持平台 1.4 Do ...

  4. Docker快速入门

    Docker快速入门 ​ 学习资料: [狂神说Java]Docker最新超详细版教程通俗易懂_哔哩哔哩_bilibili 文章目录 Docker快速入门 1.Docker概述 1.1 Docker 为 ...

  5. Docker 快速入门(一文上手 Docker)

    通过本篇文章,就可以达到在 Window 或 Linux 上手 Docker(有点长,可以根据目录选择你需要的内容看) 文章图片没有带过来,涉及的图片较多,就不一一挪了,大家可以直接看我 GitCha ...

  6. Docker快速入门实践-纯干货文章

    Docker快速入门实践-老男孩高级架构师课程内容,如果细看还能发现讲解视频呦!小伙伴们赶紧猛戳吧! 老男孩高级架构师内部学员实践文档分享! Docker快速入门实践-纯干货文章 老男孩教育2016启 ...

  7. MinIO Docker 快速入门 ​​​​​​​

    MinIO Docker 快速入门 前提条件 您的机器已经安装docker. 从 这里下载相关软件. 在Docker中运行MinIO单点模式. MinIO 需要一个持久卷来存储配置和应用数据.不过, ...

  8. MinIO Docker 快速入门

    MinIO Docker 快速入门 前提条件 您的机器已经安装docker. 从 这里下载相关软件. 在Docker中运行MinIO单点模式. MinIO 需要一个持久卷来存储配置和应用数据.不过, ...

  9. Docker快速入门总结笔记

    文章目录 1. Docker概述 2. 虚拟化技术和容器化技术 3. Docker的基本组成 4. Docker的安装 5. Docker的卸载 6. 配置阿里云镜像加速 8. Docker容器运行流 ...

最新文章

  1. 设置材质阿尔法通道和双面渲染
  2. ios 10.3 汉字的中划线
  3. 分子动力学模拟软件_分子模拟软件Discovery Studio教程(十三):构建PLS模型(3D-QSAR)...
  4. 基于Starling的mask实现
  5. maven学习系列——(七)Dependency
  6. 亚马逊API接口大全
  7. Pb语言中的类和对象
  8. 技术人员如何创业(2)---合伙人的模式
  9. KubeEdge入门到精通-KubeEdge v1.3部署指南!
  10. 腾讯云“黑石”真相——“物理私服”
  11. IMU选型、标定误差分析、AHRS组合导航
  12. 跳楼程序员让我们思考:程序员中年危机都有哪些?
  13. 系统集成十大项目管理(1)
  14. numpy array 增加一列(行)
  15. 数据挖掘综合应用:数据预处理代码实战
  16. GroupM小结1(14年8月28日)
  17. openwrt ntp服务器修改,Openwrt编译进阶-修改ROOT密码,修改默认WiFi名称,修改主机名,修改主机型号...
  18. 硬件测试之高低温测试
  19. Python dataframe.pivot()用法解析
  20. Ext JS4序列教程之一 :Layout布局

热门文章

  1. 安全帽识别系统为智能视频分析助力
  2. 最活跃FPGA论坛推荐社区
  3. leetcode-1833. 雪糕的最大数量(排序+贪心)
  4. 推荐5个堪称神器的学习网站,在家你值得拥有
  5. 2019年最全的大数据学习大纲总结,持续更新.....
  6. FFmpeg是什么?
  7. 如何做好硕士论文的排版
  8. 神经网络作文1000字,我与神经系统作文
  9. 软件设计到底是什么?
  10. rk3568 修改开机动画