Docker Swarm包含两个方面:企业级别的Docker安全集群,以及一个微服务应用编排引擎
从集群的角度,一个swarm由一个或多个Docker节点组成,唯一前提就是所有节点通过可靠的网络相连;节点会被配置为管理节点或工作节点,管理节点负责集群控制面(Control Plane),诸如监控集群状态、分发任务至工作节点等操作;工作节点接收来自管理节点的任务并执行
从编排的角度,Swarm提供一套丰富的API使得部署和管理复杂的微服务变得简单
准备:
每个节点都需要安装Docker,并且能够和swarm的其他节点进行通信
在网络方面,需要开放以下端口:
2377/tcp:用于客户端和swarm进行安全通信
7946/tcp与7946/udp:用于控制面gossip分发
4789/udp:用于基于VXLAN的覆盖网络
不包含在任何swarm中docker节点,称为运行于单引擎(single-Engine)模式,一旦加入Swarm集群,则切换为Swarm模式
服务器租用:
前三台为管理节点,后三台为工作节点
操作内容如下:
搭建安全Swarm集群
1.初始化一个全新的Swarm,在管理节点上输入命令启动swarm模式
docker swarm init --advertise-addr 172.18.178.240:2377 --listen-addr 172.18.178.240:2377 |
2.在1中的节点输入docker swarm join-token worker获取工作节点加入命令;输入docker swarm join-token manager获取管理节点加入命令;然后在工作节点和其他管理节点分别输入获取到的命令
在工作节点输入
root@iZwz9dgl8lxu1uneqs1g2wZ:~# docker swarm join --token SWMTKN-1-4tn61zy9rmy57yc1k1gog3xx3d0qfjyzfhh26p7gvhk553yl5j-6zddscu5ptks3nielojnaqhus 172.18.178.240:2377 |
在管理节点输入
[root@iZwz9b5s5jdrfwl0agyr1zZ ~]# docker swarm join --token SWMTKN-1-4tn61zy9rmy57yc1k1gog3xx3d0qfjyzfhh26p7gvhk553yl5j-cs4yra42d1ohc5zm3f3cp4vby 172.18.178.240:2377 This node joined a swarm as a manager. |
在管理节点上输入docker node ls,可以查看所有的节点
3.通过节点启动容器(定义了5个副本,每个节点都应该配置镜像加速,不然的话需要等待很长世界)
在管理节点上输入命令
[root@iZwz9ja20vilx5zt73yfowZ ~]# docker service create --name web-fe -p 8080:8080 --replicas 5 nigelpoulton/pluralsight-docker-ci |
通过命令查询容器启动情况docker service ps web-fe
通过命令查看容器的详细信息
docker service inspect --pretty web-fe
执行的命令的解析:
docker swarm init –advertise-addr IP:PORT --listen-addr IP:PORT
--advertise-addr 指定其他节点连接到当前管理节点的IP和端口
--listen-addr 指定用于承载swarm流量的IP和端口
关于swarm管理器高可用HA:
swarm实现了一种主从方式的多管理节点的HA,主节点的功能是变更配置或发送任务到工作节点,而备用的非活动管理节点接收到swarm命令后转发给主节点
swarm使用Raft共识算法的一种具体实现来支持管理节点的HA,而关于HA的最佳实践原则:
有利于减少脑裂情况的出现机会;假设系统中有四个管理节点,当发生网络分区时,可能会在每个分区有两个管理节点。而每个分区都无法知道另一个分区的节点是否可用,无法确认本分区是否掌握大多数,掌握大多数管理节点的分区能够继续堆集群进行管理。
内置swarm的安全机制
存在的问题:一个旧的管理节点重启后会自动解密并获取Raft数据库中长时间序列的访问权限,进行备份恢复的时候可能会抹掉最新的swarm配置
Docker提供自动锁机制来锁定swarm
创建集群时候启用锁机制:
docker swarm init –autolock
已存在的集群启用锁机制:
docker swarm update –autolock=true
副本服务和全局服务
服务默认的复制模式是副本模式,此模式下系统会部署期望数量的服务副本,并尽可能均匀地将各个副本分布在整个集群中
服务的另一个模式是全局模式,此模式下,每个节点上仅运行一个副本,通过命令docker service create 传递--mode global部署
服务扩缩容
docker service scale web-fe=10
删除服务
docker service rm web-fe
滚动升级
覆盖网络:创建于底层异构网络上的一个新的二层容器网络,接入该网络的容器间可以相互通讯
docker network create -d overlay uber-net
docker network ls
创建服务并将其接入uber-net网络
docker service create --name uber-service --network uber-net -p 80:80 --replicas 12 nigelpoulton/tu-demo:v1
解析:将服务命名为uber-service,使用--network参数声明副本连接到uber-net网络,在整个swarm中将80端口暴露并将其映射到12个容器副本中的80端口,最后声明所有的副本都基于nigelpoulton/tu-demo:v1镜像
swarm中流量的使用模式
默认模式为入站模式,所有节点上都开放80端口,即使节点上并没有启动服务副本,而访问没有副本的节点的请求会被转发到有服务副本的节点
主机模式,仅在运行有容器副本的节点上开放端口,使用主机模式的语法
docker service create --name uber-service –network uber-net --publish published=80,target=80,mode=host --replicas 12 nigelpoulton/tu-demo:v1
滚动升级镜像
通过变更服务期望状态的方式来更新运行中的服务
docker service update --image nigelpoulton/tu-demo:v2 --update-parallelism 2 --update-delay 20s uber-service
--update-parallelism 2 每次使用新镜像更新两个副本
--update-delay 20s 更新之间有20s延迟
故障排错和日志服务
docker中的支持的日志驱动引擎比较多,json-file/journald/syslog/splunk/gelf等,大部分引擎支持通过docker service logs查找日志(json-file/journald)
需要修改日志驱动的话,编辑daemon.json配置文件,如
{
“log-driver”:”systlog”
}
也可以启动容器时设置
docker service create --logdriver (--log-opts)
服务日志正常工作的前提:容器内的应用程序运行于PID为1的进程,并且将日志发送给STDOUT,错误信息发送给STDERR,日志驱动会将这些日志转发到其配置指定的位置
--follow 追踪日志
--tail 显示最近的日志
--details 获取额外细节
Libnetwork是docker对容器网络模型(CNM)的一种实现,提供Docker核心网络架构的全部功能
CNM定义三个基本要素
沙盒:一个独立的网络栈,包括以太网、端口、路由表以及DNS配置
终端:虚拟网络接口,主要职责是创建连接
网络:交互的终端的集合
单机桥接网络
docker上最简单的网络,只能在单个docker主机上运行,并且只能与所在的docker主机上的容器连接
桥接(意味着这是802.1.d协议的一种实现,一个二层交互机)
每个Docker主机上都有一个默认的单机桥接网络,除非通过命令行创建容器时指定参数--network ,否则默认情况下,新建的容器都会连接到该网络。
Linux主机上,默认的bridge网络被映射到内核中为docker0的Linux网桥
新建本地网桥,并使用工具查看对应的linux上网桥
安装工具bridge-utils
yum install bridege-utils
查看当前linux网桥
新建单机桥接网络
新建容器连接网络localnet
容器已经桥接到网络localnet上
PS:默认的bridge网络上不支持通过Docker DNS服务进行域名解析,自定义的桥接网络可以
新建容器,让两个连接在同一个网络上的容器通讯
c2容器运行一个本地DNS解析器,该解析器将请求转发到docker内部的DNS服务器中
通过容器端口映射到主机端口也能实现相似的功能
其他命令解析:
docker network inspect提供docker网络的详细配置信息
docker network prune删除docker主机上全部未使用的网络
docker network rm 删除docker主机上的网络
覆盖网络解决的问题:不同网络下不同主机上的容器的通讯问题
swarm模式下测试覆盖网络
机器2台一个管理节点,一个工作节点
离开之前的swarm:docker swarm leave
获取更多帮助:docker swarm --help
管理节点上运行命令
成功创建一个覆盖网络,能够连接swarm集群内的所有主机,该网络还包含一个TLS加密的控制层,如果想对数据层加密,只需在命令中增加-o encrypted参数
服务连接覆盖网络
work节点查看记录
测试覆盖网络
获取容器ip
进入容器内
容器内安装iputils-ping,先更新apt-get update
ping ip
链路追踪
覆盖网络的工作原理
数据主要分两类,持久化和非持久化
非持久化的存储自动创建,从属于容器,生命周期与容器相同,非持久化的数据存储的位置为:/var/lib/docker/
持久化数据示例:
创建和管理容器卷
删除未装入到某个容器或者服务的所有卷:docker volume prune
删除指定卷:docker volume rm
卷在容器和服务中的使用
docker自动创建命令中的volume
卷创建后,其生命周期与容器就不再绑定,即使容器销毁,卷的数据记录依然存在
共享存储存在的问题:
如果两个容器共用一个卷,容器写入数据的时候,可能会利用到缓存,而不是直接将数据写入到卷中,当多个容器同时写入数据的时候,无法控制数据写入的顺序,这样就会导致数据的不一致。
Docker stack通过提供期望状态、滚动升级、简单易用、扩缩容、健康检查等特性简化应用管理
安装git(yum install -y git)拉取项目代码
docker-stack.yml文件解析
version: "3.2"//版本号3.0以上
services: reverse_proxy: image: dockersamples/atseasampleshopapp_reverse_proxy ports://默认端口映射使用Ingress模式,意味着集群中每个节点对应的端口都可以访问,即使节点没有运行副本 - "80:80"//端口映射 - "443:443" secrets: - source: revprox_cert//密钥以普通文件的形式挂载到服务副本中 target: revprox_cert - source: revprox_key target: revprox_key networks: - front-tier
database: image: dockersamples/atsea_db environment://服务副本注入环境变量,定义数据库用户、数据库密码位置、数据库服务名称 POSTGRES_USER: gordonuser POSTGRES_DB_PASSWORD_FILE: /run/secrets/postgres_password POSTGRES_DB: atsea networks: - back-tier secrets: - postgres_password deploy://部署约束,当前服务只能运行于worker节点上 placement: constraints: - 'node.role == worker'
appserver: image: dockersamples/atsea_app networks: - front-tier - back-tier - payment deploy: replicas: 2 update_config://定义服务滚动升级的操作 parallelism: 2//并行更新2个 failure_action: rollback//升级失败后自动回滚 placement: constraints: - 'node.role == worker' restart_policy://容器异常退出重启策略 condition: on-failure delay: 5s max_attempts: 3 window: 120s secrets: - postgres_password
visualizer: image: dockersamples/visualizer:stable ports: - "8001:8080" stop_grace_period: 1m30s //设置优雅停机时间 volumes: //用于挂载提前创建的卷或者主机目录到某个服务副本中 - "/var/run/docker.sock:/var/run/docker.sock" //挂载到副本服务中,等价于给予容器查询和管理docker daemon的能力 deploy: update_config: failure_action: rollback placement: constraints: - 'node.role == manager'
payment_gateway: image: dockersamples/atseasampleshopapp_payment_gateway secrets: - source: staging_token target: payment_token networks: - payment deploy: update_config: failure_action: rollback placement: constraints: - 'node.role == worker' - 'node.labels.pcidss == yes' // 满足自定义标签的节点部署
networks://默认情况下使用overlay驱动 front-tier: back-tier: payment://默认情况下,覆盖网络的所有控制层都是加密的,如需加密数据层可采用如下方式:docker network create 中指定参数-o encrypted或stack文件中driver_ops下使用encrypted driver: overlay driver_opts: encrypted: 'yes'
secrets: postgres_password: external: true//表示密钥都是必须存在 staging_token: external: true revprox_key: external: true revprox_cert: external: true |
部署应用
创建swarm
节点重命名
添加节点标签
添加节点标签到wrk-1
创建密钥
创建键值对
创建密钥
[root@iZwz93u0wgvqu3n08399rzZ ~]# docker secret create revproxy_cert domain.crt zpngq6161nycynlekvhw3puaz [root@iZwz93u0wgvqu3n08399rzZ ~]# docker secret create revproxy_key domain.key wc3z4oc6vj6phn1n0kgk6mek2 [root@iZwz93u0wgvqu3n08399rzZ ~]# docker secret create postgres_password domain.key rhgvnohp9xeiqkxp6nnr6w9df [root@iZwz93u0wgvqu3n08399rzZ ~]# echo staging |docker secret create staging_token - k3awozs8ofhj98kwtv7lgzn2c [root@iZwz93u0wgvqu3n08399rzZ ~]# docker secret ls ID NAME DRIVER CREATED UPDATED rhgvnohp9xeiqkxp6nnr6w9df postgres_password 51 seconds ago 51 seconds ago zpngq6161nycynlekvhw3puaz revproxy_cert 2 minutes ago 2 minutes ago wc3z4oc6vj6phn1n0kgk6mek2 revproxy_key About a minute ago About a minute ago k3awozs8ofhj98kwtv7lgzn2c staging_token 12 seconds ago 12 seconds ago |
部署服务
删除服务
修改文件后重新部署
docker stack deploy -c docker-stack.yml seastack
命令解析:
docker stack deploy 用于根据stack文件部署和更新stack服务
docker stack ls 列出swarm集群中的全部stack,包括每个stack拥有多少服务
docker stack ps 列处某个已经部署的stack相关详情
docker stack rm 从swarm集群中移除stack,移除操作执行前不会进行二次确认
安全的本质是分层,拥有更多的安全层,就拥有更多的安全性。
docker中的安全层
Docker平台技术 |
密钥管理 Docker内容信任 安全扫描 Swarm模式 |
操作系统技术 |
安全计算 强制访问控制(MAC) 系统权限 控制组 内核命名空间 |
Linux安全技术
该技术能够将操作系统OS进行拆分,使得一个操作系统看起来像多个相互独立的操作系统一样。每个命名空间都有自己的IP和对应的全部端口。
Docker容器是由各种命名空间组合而成的,Docker容器本质是命名空间的有组织集合
主机的命名空间
进程IP命名空间:Docker使用PID命名空间为每个容器提供相互独立的容器树。
网络命名空间:Docker使用NET命名空间为每个容器提供相互隔离的网络栈。
挂载点命名空间:每个容器都有相互隔离的根目录/,容器内的进程只能访问自己容器独立挂载的命名空间
进程内通讯命名空间:Docker使用IPC命名空间载容器内提供共享内存。IPC提供的共享内存载不同的容器间也是相互独立。
用户命名空间:Docker运行用户使用USER命名空间将容器内用户映射到linux主机不同的用户上。
UTS命名空间:Docker使用UTS命名空间为每个容器提供自己的主机名称
命名空间用于隔离,控制组用于限额,CGroup允许用户设置一些限制来保证不会存在单一容器占用全部的公共资源。
Capability机制实现用户以root身份允许容器,还能移除非必须的root能力
允许用户在启动容器时不设置相应策略,还可以根据需求设置合适的策略
Docker使用过滤模式下的Seccomp来限制容器对宿主机内核发起的系统调用
Docker平台安全技术
略
略