优势:
1.启动快。
传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。
2.更高效的利用系统资源。
由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。
3.一致的运行环境
开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。
4.持续交互和部署
对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。
使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合 持续集成(Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) 系统进行自动部署。
而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。
5.更轻松的迁移
由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。
6.更轻松的维护和扩展
Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。
二 概念
docker有三个概念。1.镜像(image)。2.容器(container)。3.仓库(repository)。
(1) 镜像image
操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 Ubuntu 18.04 就包含了完整的一套 Ubuntu 18.04 最小系统的 root 文件系统。
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
(2)关于镜像分层存储。
因为镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。
镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。(这就相当于镜像实质上只会按层递增体积,文件在那层创建的只能在那层彻底清除,后续层删除只是假删除。)
分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。
(3) 容器 container
镜像 (image) 和容器 (container) 的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root· 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。(容器相当于沙箱,隔离宿主机起的进程,即使出现病毒也是威胁不到宿主机的)
镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为 容器存储层。docker run image —>container 容器添加存储层。
容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。
按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。(绑定宿主目录是一个好的方法,相当于docker容器的某个目录打到了宿主机的某个目录)
数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。
(4) 注册 Docker Registry
镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。
一个 Docker Registry 中可以包含多个 仓库(Repository);每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像。
(registry理解的就是一个注册中心,里面包括不同系统项目的仓库,而一个仓库就是一个镜像的集合,每个镜像对应的tag就是一个版本的镜像。)
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。
以 Ubuntu 镜像 为例,ubuntu 是仓库的名字,其内包含有不同的版本标签,如,16.04, 18.04。我们可以通过 ubuntu:16.04,或者 ubuntu:18.04 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 ubuntu,那将视为 ubuntu:latest。
仓库名经常以 两段式路径 形式出现,比如 jwilder/nginx-proxy,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。
(我们可以下载docker官方registry的镜像,由于外网也可以使用国内的加速器,例如阿里云。这种镜像都是在公有registry中的,而我们企业开发时,就是私有的registry,我们把创建的私有镜像发布到docker registry注册中心。如:harbor)
三 安装docker
安装详情参照— Ubuntu - Docker — 从入门到实践
本篇文章基于Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-142-generic x86_64) 编写。
查询ubuntu系统的配置:https://blog.csdn.net/kinglyjn/article/details/53584652
可以用这个命令 : cat /etc/os-releas 查看当前的Ubuntu信息
旧版本的 Docker 称为 docker 或者 docker-engine,使用以下命令卸载旧版本:
sudo apt-get remove docker \
docker-engine \
docker.io
使用 APT 安装
由于 apt 源使用 HTTPS 以确保软件下载过程中不被篡改。因此,我们首先需要添加使用 HTTPS 传输的软件包以及 CA 证书。
$ sudo apt-get update
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
鉴于国内网络问题,强烈建议使用国内源,官方源请在注释中查看。
为了确认所下载软件包的合法性,需要添加软件源的 GPG 密钥。
$ curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
官方源
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
然后,我们需要向 source.list 中添加 Docker 软件源
$ sudo add-apt-repository \
"deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu \
$(lsb_release -cs) \
stable"
# 官方源
# $ sudo add-apt-repository \
# "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
# $(lsb_release -cs) \
# stable"
安装 Docker CE
更新 apt 软件包缓存,并安装 docker-ce:
$ sudo apt-get update
$ sudo apt-get install docker-ce
启动 Docker CE
$ sudo systemctl enable docker
$ sudo systemctl start docker
配置国内镜像加速
镜像加速器 - Docker — 从入门到实践
对于使用 systemd 的系统,请在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件)
{
"registry-mirrors": [
"https://dockerhub.azk8s.cn",
"https://reg-mirror.qiniu.com"
]
}
注意,一定要保证该文件符合 json 规范,否则 Docker 将不能启动。 然后重启docker
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
docker run hello-world 看一下是否成功。
volume卷
主机中的文件映射到容器里。达到主机改动文件,容器也能得到改动。还能达到持久化的作用。
- 拿nginx来举例。nginx配置了一个server,这个server指定的了一个文件的目录。然后把nginx起起来了。我们访问nginx配置的server域名做web开发。而此时我们想改代码是需要在nginx这个docker起的容器里面修改代码的。docker exec -it nginx bash 进去nginx,然后改改改。然后我们想移植到其他服务器上时,就只能把这个容器commit成一个镜像,然后push到私服,然后其他服务器再拉下来,然后改改改。
上述这个过程缺点太多了,比如数据没有持久化,比如commit造成镜像的一步步臃肿等等。
- 代替的,我们可以使用卷。将上述server配置的root文件夹由宿主机映射进去,宿主机是从git拉的代码(如果你想说,刚刚也可以Git啊,我觉得需要注意docker的使用建议。尽量保持镜像提供单一服务),然后直接映射进容器的对应目录了。不需要exec操作。还能保证数据在服务器持久化了。
真实操作一下
- 下面这行命令会将容器中的 /etc/nginx 目录映射到 /var/lib/docker/volumes/volumeTest/_data 中
docker run -p 81:80 -d --name nginx81 -v volumeTest:/etc/nginx nginx:80
volumeTest是随便起的名,如果不写绝对路径会映射本地的docker设置的默认位置
查看 volumeTest 这个卷
docker volume inspect volumeTest
[
{
"CreatedAt": "2019-12-16T15:23:30+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/volumeTest/_data",
"Name": "volumeTest",
"Options": null,
"Scope": "local"
}
]
卷像是一个链接。 文件权限是与docker container 共享的。
-
在卷host映射的目录改 chmod 777 nginx.conf docker exec 看 /etc/nginx 也是发生改变了的。
-
下面这个命令是将宿主机的 /home/zy/docker/nginx81_test 目录映射到容器中的 /etc/nginx
- 重点: 这么写会覆盖掉容器中 /etc/nginx 下的数据为nginx81_test目录中的数据。
docker run -p 82:80 -d --name nginx82 -v /home/zy/docker/nginx81_test:/etc/nginx nginx:80
所以如上这个这么写 nginx是跑不起来的。
docker run -p 82:80 -d --name nginx82 -v /home/zy/docker/nginx81_test:/etc/nginx/test nginx:80
这个命令就可以测试宿主机真的和容器中的/etc/nginx/test目录映射上了。
我们可以在宿主机直接操作 /home/zy/docker/nginx81_test 就可以将改动映射进容器nginx82 而不用exec进入容器
- 以上宿主机和容器中的目录都会被创建。 而且容器中的目录会被宿主机中的目录覆盖掉。 即宿主机中的文件夹永远会覆盖掉容器中的文件夹。
对于文件挂载
- 禁止将不存在的文件挂载进container中已经存在的文件上
- 存在的文件挂载进container中将会覆盖container中对应的文件, 若文件不存在则新建
对于文件挂载的应用场景,可以修改配置文件。然后restart docker container
对于文件夹挂载一般挂载的是日志文件。
-
改user/group 这个与UID有关 /etc/passwd /etc/group中的那个数字
容器指定的UID映射成宿主机对应的UID 这样对应的用户很有可能是不一样的。
-
宿主机的挂载目录,即使docker container 删除了也是存在的。 删之前啥样,删之后啥样。
-
注意容器的目录不能是相对目录
-
dockerfile的方式挂载数据卷的时候使用volume 关键字 但是只能生成随机的目录,不能生成指定的目录。
Docker-compose
简单介绍一下项目中会使用到的属性。
1.安装
sudo curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
2.给compose权限
sudo chmod +x /usr/local/bin/docker-compose
3.卸载 docker-compose
sudo rm /usr/local/bin/docker-compose
4.看docker的版本
docker-compose version
/etc/docker/daemon.json 是docker的配置文件
5.docker-compose 写完docker-compose.yml文件后,只需执行 docker-compose up -d 命令会进行构建镜像,创建服务,启动服务等等一系列操作。
https://yeasy.gitbooks.io/docker_practice/appendix/command/docker.html 里面有图不错的。
6.docker-compose.yml文件的一些参数。 docker-compose.yml文件会动态读取系统环境变量和当前目录下的.env文件中的变量 ${var_name}使用、
下面是yml常使用的属性。
version: "2" #指定使用docker-compose的版本
services: #固定
web: #子集
image: nginx:latest #要拉的镜像。本地不存在,compose会拉取。
# build: #build 可以指定所需构建镜像的dockerfile目录 如果仅指定dockerfile的位置可以直接 build . 这样,还有其他操作就细分context等。
# context: ./docker/ #context 指定所需构建镜像的dockerfile目录
ports: #配置端口
- "80:80" # - 在yml中是list
restart: always #down 掉重启 指定容器退出后的重启策略为始终重启
volumes: #映射的数据卷
- ./app:/www/web
- ./nginx/conf:/etc/nginx
- ./nginx/logs:/www/web_logs
container_name: web-nginx #启动的container名称
networks: #配置容器连接的网络
- code-network
depends_on: #当前子集web 所依赖的服务 需要注意不会等到依赖服务完全启动才启动当前服务。
- php
env_file:
- ./comm.env #env_file文件可以使用docker-compose -f xx.yml指定的配置文件的目录。这个可以使用environment设置变量。
mysql:
# build:
# context: ./docker_file/mysql
image: mysql:5.7.23
container_name: mysql
ports:
- "3306:3306"
volumes:
- /data/mysql/data:/var/lib/mysql
- /data/mysql/conf.d:/etc/mysql/conf.d
restart: always
environment:
- MYSQL_ROOT_PASSWORD=test #设置变量
networks:
- code-network
networks: #设置当前的这个compose的网络名称及使用的网络连接方式是bridge
code-network:
driver: bridge
Docker 命令图
图片来源:https://yeasy.gitbooks.io/docker_practice/appendix/command/docker.html
Docker 网络
什么是网卡:连接计算机网络的硬件资源。 常用查网卡的命令 ifconfig [lo eth0]
什么是集线器:一个口收信号,原封不动的发送给所有其他的口,表现在物理层
什么是网桥:网桥也叫桥接器,是连接两个局域网的一种存储/转发设备,工作在数据链路层,以太网中,数据链路层就是Mac地址,相当于一个桥梁,只有符合的mac地址能出来。
docker的网络模式有四种,bridge host container none
bridge模式(默认)
当docker启动时会在主机创建一个docker0的虚拟网桥,此主机启动的容器会连接到这个虚拟网桥上。这样容器之间就能通信了。从docker0子网中分配一个IP给容器使用,并设置docker0的IP为容器的默认网关。在主机上创建一对虚拟网卡,veth pair设备 docker将veth pair 的一端放到新创建的容器中,并命名为eth0(容器的网卡)另一端放在主机中,以vethxxx命名,并将这个网络设备加到docker0网桥中。
使用时:建议用docker-compose 指定network 连接在一起就可以了,非常方便。提供demo
version: "2"
services:
nginx:
image: nginx:latest
ports:
- "80:80"
restart: always
networks:
- test-network
depends_on:
- php
mysql:
image: mysql:5.7
volumes:
- ./db/mysql/data:/var/lib/mysql
- ./db/mysql/conf.d:/etc/mysql/conf.d
ports:
- "3306:3306"
restart: always
environment:
- MYSQL_ROOT_PASSWORD=12345678
networks:
- test-network
php:
image: php:7.2.18
restart: always
depends_on:
- mysql
networks:
- test-network
networks:
test-network:
driver: bridge
Host
当使用这种模式时,容器不再是一个独立的network ,而是和宿主机使用一个 ip:port 除了网络之外的是隔离的。
Container
这个模式指定新创建的容器和已经存在的容器共享一个network 新容器不会创建自己的网卡,配置自己的ip而是跟指定的容器共享一个ip端口
None
不对docker容器进行网络配置
综上:
最常使用的是host和bridge
补充转自:https://www.qikqiak.com/k8s-book/docs/7.Docker%E7%9A%84%E7%BD%91%E7%BB%9C%E6%A8%A1%E5%BC%8F.html
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)