Docker
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口
使用场景
- 持续集成
- 可伸缩的云服务
- 微服务架构
容器与虚拟机
虚拟机最大的缺点就是依赖其专用的操作系统
Docker架构
- 镜像与容器
- 容器是镜像的实例
安装
- 安装脚本
wget https://get.docker.com
引擎
Docker引擎由如下主要的组件构成:Docker客户端(Docker Client)、Docker守护进程(Docker daemon)、containerd以及runc。它们共同负责容器的创建和运行
LXC提供了对诸如命名空间(Namespace)和控制组(CGroup)等基础工具的操作能力,它们是基于Linux内核的容器虚拟化技术
Docker公司开发了名为Libcontainer的自研工具,用于替代LXC
runc:
- 创建容器
containerd:
- 容器的生命周期管理
启动容器的过程:
容器运行时与Docker daemon是解耦的,对Docker daemon的维护和升级工作不会影响到运行中的容器
shim:
- 保持所有STDIN和STDOUT流是开启状态
- 将容器的退出状态反馈给daemon
镜像
镜像使用
- 搜索镜像
docker search name
- 拉取镜像
docekr pull name<:tag>
- 删除镜像
docker rmi 镜像ID
docker image rm $(docker image ls -q) -f
标签
在镜像名后面的:xxx 代表标签
没有标签的镜像被称为悬虚镜像
分层
docker 会复用已存在的镜像层
镜像仓库
搭建
docekr pull registry
docker run -di --name=registry 5000:5000 registry
上传镜像到私服
docker tag nginx 127.0.0.1:5000/nginx
docker push 127.0.0.1:5000/nginx
容器
持久化
容器在停止后启动写入的数据仍会存在
但是volume才是持久化的首选
重启策略
在指定事件或者错误后重启来完成自我修复
- always
- unless-stoped
- on-failed
容器使用
- 查看容器
docker ps
- 运行一个容器
docker run -p 8080:80 -d daocloud.io/nginx
- 复制文件到容器中
docker cp index.html e07dc4e0236a://usr/share/nginx/html
- 从容器中复制出文件
docker cp name:容器文件路径 宿主路径
- 停止容器
docker stop name
# 优雅关闭并删除:stop rm
- 启动容器
docker start name
- 进入容器内部
docker exec -it <name> bash
目录挂载
- 在启动容器时,使用
-v
参数
- 在启动容器时,使用
查看容器信息
docker inspect name
- 查看容器日志
docker logs name
常用软件部署
- mysql
# 将宿主机33306映射到容器3306,指定root密码为123
docker run -di --name=mysql1 -p 33306:3306 -e MYSQL_ROOT_PASSWORD=123 mysql
- tomcat
docker run -di --name=mytomcat -p 9000:8080 -v /usr/local/webapps:/usr/local/tomcat/webapps tomcat
- nginx
docker run -di --name=mynginx2 -p 8080:80 nginx-update
迁移与备份
- 保存镜像
docker commit -m 'update' e07dc4e0236a nginx-update
- 保存为压缩包
docker save -o nginx-update.tar nginx-update
- 把压缩包恢复成镜像
docker load -i nginx-update.tar
容器化
Dockerfile
编写Dockerfile文件:
FROM ubuntu
MAINTAINER MY
RUN apt-get update
RUN apt-get install nginx -y
COPY index.html /var/www/html
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
EXPOSE 80
每一个RUN指令会新增一个镜像层。因此,通过使用&& 连接多个命令以及使用反斜杠(\ )换行的方法,将多个命令包含在一个RUN指令中,通常来说是一种值得提倡的方式
根据文件构建镜像:
docker build -t='name' .
DockerMaven插件
- 开启docker接受远程操作
- 添加maven插件
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.12</version>
<configuration>
<!-- 注意imageName一定要是符合正则[a-z0-9-_.]的,否则构建不会成功 -->
<!-- 详见:https://github.com/spotify/docker-maven-plugin Invalid repository name ... only [a-z0-9-_.] are allowed-->
<imageName>my-pc:5000/${project.artifactId}:${project.version}</imageName>
<baseImage>java</baseImage>
<entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
<dockerHost>http://my-pc:2375</dockerHost>
</configuration>
</plugin>
- JDK8以上的版本需要添加如下依赖
<dependencies>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
- 构建并推送
mvn clean package docker:build -DpushImage
推送到仓库
docker images push
多阶段构建
FROM xxx AS T1
FROM xxx AS T2
COPY --from=T1 ...
最佳实践
利用构建缓存:
- 执行命令时,Docker会检查构建缓存中是否存在基于同一基础镜像,并且执行了相同指令的镜像层
合并镜像:
- 执行docker image build 命令时,可以通过增加--squash 参数来创建一个合并的镜像
no-install-recommends:
- 若使用的是APT包管理器,则应该在执行apt-get install 命令时增加no-install-recommends 参数。这能够确保APT仅安装核心依赖(Depends 中定义)包
不要安装MSI包(Windows)
Compose
编写docker-compose.yml:
version: "3.5"
services:
redis:
image: "redis:alpine"
networks:
my-net:
nginx:
image: "nginx"
networks:
my-net:
networks:
my-net:
volumes:
my-net:
启动:
docker-compose up
Docker 网络
CNM: 定了Docker网络架构的基础组成要素
Libnetwork是CNM标准的实现
docker network ls # 列出可用网络
docker run -d --network my-net # 指定容器网络
如果在相同网络中继续接入新的容器,那么在新接入容器中是可以通过的容器名称来进行网络通信的
网络类型
- Bridge:: 单机桥接网络 Docker设计的NAT网络模型(默认类型)
- 只能在单个Docker主机上运行,并且只能与所在Docker主机上的容器进行连接
docker network create -d bridge localnet
- Host:与主机共享Network Namespace,--net=host
- overlay:多机覆盖网络
- 接入现有网络
- None::不为容器配置任何网络功能,没有网络 --net=none
- Container:与另一个运行中的容器共享Network Namespace,--net=container:containerID
- 端口映射
# 将本机8080端口映射到容器80端口
docker run -p 8080:80 <name>
# 将本机端口随机与容器端口映射
docker run -P <name>
持久化
每个Docker容器都有自己的非持久化存储。非持久化存储自动创建,从属于容器,生命周期与容器相同
持久化是将数据存储在卷上。卷与容器是解耦的
卷类型:
- 块存储
- 适用于对小块数据的随机访问负载
- 文件存储
- 包括NFS和SMB协议的系统
- 对象存储
- 适用于较大且长期存储的、很少变更的二进制数据存储。通常对象存储是根据内容寻址
卷操作
docker volume create myv
docker volume inspect myv
docker run ... --mount source=bizvol,target=/vol # 指定容器存储卷
安全
Docker 平台安全技术:
- Swarm模式
- 加密节点ID。
- 基于TLS的认证机制。
- 安全准入令牌。
- 支持周期性证书自动更新的CA配置。
- 加密集群存储(配置DB)。
- 加密网络
- 内容信任
- 通过 Docker Hub 信任内容
- 密钥
- 使用
docker secret
管理密钥
- 使用
Namespace
Docker 提供的容器环境是和 Linux 内核隔离的。想要实现这种隔离,就需要用到 Namespace 机制 Namespace的隔离并不够彻底
Capabilities
提供了更细粒度的授权机制,它定义了主体能够进行的某一类操作
- 拒绝所有的挂载操作;
- 拒绝部分文件的操作,比如修改文件所有者;
- 拒绝内核模块加载
CGroups
利用 CGroups 机制来实现对容器中内存、CPU 和 IO 等的限制
守护进程安全性
守护进程,具备操控 Docker 容器的全部权限
如果守护进程提供的API接口没有认证,则很容易被入侵
镜像安全
- 最小精简镜像
- 使用User 指令指定运行用户
容器管理
Rancher
可以对容器进行分类、分环境管理,以图形化界面操作docker Rancher是一个开源的企业级全栈化容器部署及管理平台。Rancher为容器提供一揽 子基础架构服务:CNI兼容的网络服务、存储服务、主机管理、负载均衡、防护墙…… Rancher让上述服务跨越公有云、私有云、虚拟机、物理机环境运行,真正实现一键式应 用部署和管理
- 主机
- 应用
- 容器
- 服务
- 扩容缩容
influxDB
InfluxDB是一个由InfluxData开发的开源时序型数据库。它由Go写成,着力于高性能地查询与存储时序型数据。InfluxDB被广泛应用于存储系统的监控数据,IoT行业的实时数据等场景
cAdvisor
CAdvisor是Google开源的一款用于展示和分析容器运行状态的可视化工具。通过在主机上运行CAdvisor用户可以轻松的获取到当前主机上容器的运行统计信息,并以图表的形式向用户展示
Grafana
grafana 是一款采用 go 语言编写的开源应用,主要用于大规模指标数据的可视化展现,是网络架构和应用分析中最流行的时序数据展示工具,目前已经支持绝大部分常用的时序数据库