开发者学堂课程【4天Docker 实战-1024程序员节创造营公益课:docker 实际工作案例实现】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/892/detail/14274
docker 实际工作案例实现
目录:
一、数据持久化应用场景
二、永久存储文件类型
三、数据持久化类型
四、Harbor 仓库概念
五、Harbor 仓库作用
六、Harbor 仓库安装及其使用
七、微服务概念
八、微服务特点
九、微服务性质及其部署
十、微服务 Jenkins
十一、数据持久化案例
一、数据持久化的场景
1.永久存储文件
配置文件,日志文件,应用数据,缓存文件
容器中的数据可以存储在容器层。但是将数据存放在容器层存在以下问题:
(1) 数据不是持久化。意思是如果容器删除了,这些数据也就没
(2) 主机上的其它进程不方便访问这些数据
(3) 对这些数据的 I/O 会经过存储驱动,然后到达主机,引入了一层间接层,因此性能会有所降
2. 数据持久化类型
方式一:volumes
存于主机文件系统中的某个区域,由 Docker 管理(/var/lib/docker/volumes/ )。非 Docker 进程不应该修改这些数据。你可以把它当做容器数据持久化专门的磁盘分区。
多个容器这间共享数据宿主机不保证存在固定的目录结构持久化数据到远程主机或者云存储而非本地需要备份、迁移、合并数据时。停止 container ,将 volume 整体复制,用于备份、迁移、合并等。
特点:
1:volumes 是 Docker 中持久化数据的最好方式。因为和容器解耦度更高。
2:多个容器可以同时访问一个 volumes 。
3:远程主机或非本地常用该方式。(架构)
4:首先需要创建。之后再进行使用。
使用:
docker volume create test1
docker run -itd -p 8800:80 -v test1:/usr/share/nginx/html nginx:v1
创建:docker volume create
删除某个卷:docker volume rm 卷名
删除所有未使用的卷:docker volume prune
列出所有卷:docker volume ls
查看某个卷的信息:docker volume inspect 卷名
挂载到容器:-v 或 –volume 。如果是 Docker17.06 或更高:推荐使用 –mount。(同 bind mount)
挂载类型:key 为 type,value 为 bind、volume 或 tmpfs
挂载源:key 为 source 或 src,对于命名卷,value 为卷名,对于匿名卷,则忽略
容器中的挂载点:key 为 destination、dst 或 target,value 为容器中的路径
读写类型:value 为 readonly,没有 key
volume-opt 选项,可以出现多次。比如 volume-driver=local,volume-opt=type=nfs,…
第一个域:对于命名卷,为卷名;匿名卷,则忽略,此时会创建匿名卷
第二个域:容器中的挂载点
第三个域:可选参数,由’,'隔开,如 ro
-v 或 —volume:由3个域组成,’:’分隔
—mount:由多个’,’隔开的键值对组成
方式二:bind—mount
将宿主机中的文件、目录 mount 到容器上。质上是宿主机、container 之间共享宿主机文件系统。这种持久化方法更导致 container 与宿主机的耦合过于紧密,所以不推荐使用。
特点:
1:它更像1对1的夫妻。耦合度较高。
2:一些监控类 container ,通过读取宿主机固定文件中的数据实现监控等。
3:常用于临时共享文件(如配置文件等)或源码文件。
使用:
docker run -itd -p 8801:80 -v /var/log/cont/apache1:/var/log/httpd/
apache:new2
挂载到容器:-v 或—volume 。如果是 Docker17.06 或更高:推荐使用 —mount。(同 volumes)
-v 或 –volume:由3个域组成,’:'分隔
第一个域:对于命名卷,为卷名;匿名卷,则忽略,此时会创建匿名卷
第二个域:容器中的挂载点
第三个域:可选参数,由’,'隔开,如 ro
–mount :由多个’,'隔开的键值对=组成:
挂载类型:key 为 type,value 为 bind、volume 或 tmpfs
挂载源:key 为 source 或 src,value 为主机中文件或目录的路径
容器中的挂载点:key 为 destination、dst 或 target,value 为容器中的路径
读写类型:value 为 readonly,没有 key
bind-propagation 选项:key为bind-propagation,value 为 rprivate、private、rshared、shared、rslave 或 slave
一致性选项:value 为 consistent、delegated、cached。这个选项仅仅适用于Docker for Mac
–mount 不支持 z 和 Z(这个不同于 -v 和 —volume)
方式三:tmpfs
将数据存于宿主机内存中。docker 可将用户名与密码等敏感数据保存在某个数据库中,当启动需要访问这些敏感数据的 container 或者 service 时,docker 会在宿主机上创建一个 tmpfs ,然后将敏感数据从数据库读出写到 tmpfs 中,再将 tmpfs mount 到 container 中,安样能保证数据安全。当容器停止运行时,则相应的 tmpfs 也从系统中删除。
特点:
1:仅限 Linux 系统。
2:较少用,常见用于对于访问有大量读写,或安全层面考虑。
3:不会持久化,生命周期限于容器启动时。
4:多容器无法共享同一个 tmpfs
使用:
docker run -itd --name tmptest --tmpfs /root nginx:latest
二、harbor 仓库
1.概念
Docker 容器应用的开发和运行离不开可靠的镜像管理,虽然 Docker 官方也提供了公共的镜像仓库,但是从安全和效率等方面考虑,部署私有环境内的 Registry 也是非常必要的。Harbor 是由 VMware 公司开源的企业级的 Docker Registry 管理项目,它包括权限管理 (RBAC)、LDAP、日志审核、管理界面、自我注册、镜像复制和中文支持等功能
Harbor 是由 VMware 公司开源的企业级的 Docker Registry 管理项目,相比docker 官方拥有更丰富的权限权利和完善的架构设计,适用大规模 docker 集群部署提供仓库服务。
2.作用
1:企业级镜像仓库,根据企业需求创建的镜像,可以通过 harbor 实现
管理和使用。
2:主要特点功能包括:基于角色的访问控制,基于镜像的复制策略,
图形化用户界面,审计管理等。
3. 安装
1:安装并启动 docker(略)
2:安装 docker-compose1.18 以上版本。
( docker 单机容器编排工具)
• wget
https://github.com/docker/compose/releases/download/1.29.2/
docker-compose-Linux-x86_64
#从官网下载 docker-compose 二进制文件
•chmod +x docker-compose-Linux-x86_64
#添加执行权限
•mv docker-compose-Linux-x86_64 /usr/bin
#移动到系统指令目录下
tar -xvf harbor-offline-installer-v2.3.1.tgz
、
#解压
•cp harbor/harbor.yml.tmpl harbor/harbor.yml
#复制官方配置文件案例。
•vim harbor.yml
#修改配置文件中 hostname 和 https 字段。
•bash prepare && bash install.sh
#初始化并安装
4. 使用
web 页面中操作新建项目、新建人员并设置权限、匹配人员和项目。
将本地刚刚做的镜像推送到harbor共用项目仓库中。
dockertagapache:new1 192.168.28.131/library/apache:new1
使用 harbor•vim /etc/docker/daemon.json
(信任 harbor 端 IP )
{
"registry-mirrors": ["https://f9dk003m.mirror.aliyuncs.com"],
"insecure-registries":["192.168.28.131"]
}
•docker login 192.168.28.131
•docker push 192.168.28.131/library/apache:new1
挂载到容器:— tmpfs 。如果是 Docker17.06 或更高:
推荐使用— mount
挂载类型:key 为 type,value 为 bind、volume 或 tmpfs
容器中的挂载点:key 为 destination、dst 或 target,value 为容器中的路径
tmpfs-size 和 tmpfs-mode 选项
—tmpfs:直接指定容器中的挂载点。不允许指定任何配置选项
—mount:由多个’,’隔开的键值对组成
微服务
1.概念
微狭义来讲就是体积小、著名的 "2 pizza 团队"很好的诠释了这一解释(2 pizza 团队最早是亚马逊 CEO Bezos 提出来的,意思是说单个服务的设计,所有参与人从设计、开发、测试、运维所有人加起来 只需要2个披萨就够了 )。 而所谓服务,一定要区别于系统,服务一个或者一组相对较小且独立的功能单元,是用户可以感知最小功能集。
微服务是一种架构模式,它提倡的是将单体应用拆分成各个模块,充分解耦,独立构建部署,
相互之间可以协调,配合。
客户端向负载均衡器发出请求,负载均衡器向服务注册表发出请求,将请求转发到注册表中可用的服务实例。服务实例也是在注册表中注册,注销的。负载均衡可以使用可以使用 Haproxy 或者 Nginx。服务端发现模式目前基于 Docker 的主流方案主要是 Consul、Etcd 以及 Zookeeper。
Consul
Consul 提供了一个 API 允许客户端注册和发现服务。其一致性上基于 RAFT 算法。通过 WAN 的 Gossip 协议,管理成员和广播消息,以完成跨数据中心的同步,且支持 ACL 访问控制。Consul 还提供了健康检查机制,支持 kv 存储服务(Eureka 不支持)。Consul 的一些更详细的介绍可以参考之前写的一篇:Docker 容器部署 Consul 集群。
Etcd
Etcd 都是强一致的(满足 CAP 的 CP),高可用的。Etcd 也是基于 RAFT 算法实现强一致性的 KV 数据同步。Kubernetes 中使用 Etcd 的 KV 结构存储所有对象的生命周期。
关于 Etcd 的一些内部原理可以看下 etcd v3 原理分析
Zookeeper
ZK 最早应用于 Hadoop ,其体系已经非常成熟,常被用于大公司。如果已经有自己的 ZK 集群,那么可以考虑用 ZK 来做自己的服务注册中心。
Zookeeper 同 Etcd 一样,强一致性,高可用性。一致性算法是基于 Paxos 的。对于微服务架构的初始阶段,没有必要用比较繁重的 ZK 来做服务发现。
2. 特点
小:颗粒度小,且专注一件事情。
独:单独的进程。美韩中国
轻:轻量级的通信机制。德
松:松耦合,独立部署
3. 性质
(复杂性)
困境:
系统会随着业务的发展,增加越来越多的特性和功能,使得系统复杂到没有一个人能全面理解,没有一个人敢去修改原有的功能或代码。
微服务:
微服务提出以业务边界作为模块划分原则,每个模块独立进程。一个业务由很多独立的小业务组合而成,系统也是由独立的小系统组合而成,这样的好处是每个小系统都很容易被理解,一个大系统可以根据业务组合微服务,或者逐渐发展独立的微服务
代价:
微服务为了降低单个微服务的复杂性,导致整体系统的复杂性急剧增加。微服务之间的连接更加复杂,网络通讯不可靠和性能损耗,协议匹配,接口对接和转换,版本协作,微服务注册和发现,编排和调度,分布式业务和数据一致性等等复杂性都是单体架构不需要考虑的。
经验要求、k8s
(隐匿性)
困境:
软件在没有应用到业务之前,各种信息和思考大多在每个人的脑海里,很难完全呈现和想象出来。客户只是知道自己想要更多新英雄,但并不知道要具体什么样的英雄;开发设计人员知道怎么做英雄,但又不能完全理解用户需求;运维知道部署服务和上线,但又不能完全理解业务逻辑。单体架构中的各个模块隐藏在大系统的页面下,在交付之前对外界是不可见的。 导致没有人能看清全貌,各自都想把事情做到最好,但组合起来却不是客户想要的东西。
微服务:
微服务架构并没有改变软件开发过程中的隐匿性,而是通过缩短从需求到交付这段软件开发周期,减少隐匿时间,来降低软件工程总体的隐匿性。
代价:
组织必须要具备自动部署持续交付能力。假如一个系统上线需要3个小时进行部署,如果我们要持续部署,每天都部署一次,那就需要每天拿出3小时做部署,这个成本是不能接受的。
Devops
(耦合性)
困境:
假如系统从零开始做的话,头三个月开发会比较慢,因为需要搭建和熟悉一些开发、测试、部署基础设施,随着基础设施和公共组件的完善,接下来的半年到一年开发会加速,但是再往后开发速度又会逐渐降低。
因为那些一开始提高开发效率的接口、共享表、依赖组件都变成了复杂网络缠绕在一起,变成了所谓的牵一发而动全身,改一行代码都不知道会影响到什么地方。
微服务:
微服务系统的耦合性问题总是在一个可控的范围内。比如微服务独立数据库表结构,那我们根据业务需要改表结构的时候就不需要去考虑会不会影响到其他业务,因为其他业务和这个表结构完全没关系。
代价:
单纯从接口协同一致上来说,微服务架构比较糟糕。 单体架构的接口之间配合是相同的编程语言,基本上在编译时就能发现错误。而微服务的接口往往是远程服务,验证增加难度。
运维观战
(易变性)
困境:
比如某个模块的流量突然增加,或者需要大内存,单体架构只能为极少的模块增加整个系统的计算资源,又因为增加整个系统的计算资源成本很高、实施时间长,导致性能需求迟迟不能得到满足。
微服务:
微服务要求独立进程,可以完全根据需求定制不同类型的计算资源,更精细化分类的利用内存、IO、CPU 。因为小,可以更快水平扩展响应性能需求变化。更关键是,微服务小,强调独立业务价值。
小团队直接面对客户需求做决策,所有信息和想法在小范围内快速交流,业务价值流动更容易可见,更快速的响应变化。后期可以弹性扩容。
代价:
微服务架构需要改变组织结构小团队充分授权、业务交付模式。对传统组织而言,这点是最难的,尤其是大公司往往采用层级组织结构。公司层面
4. 部署应用
首先把 service-discovery 项目中的 shells 目录分别复制到 user-service 和 product-service 目录下,然后分别将 build.sh 和 release-docker.sh 脚本中的容器名称和端口号修改如下。
·user-service
:将 dockerName 修改为 userservice ,将 dockerPort 修改为2100 。
·product-service
:将 dockerName 修改为 productservice ,将 dockerPort 修改为 2200。
修改完毕后,分别执行微服务的 build.sh 脚本,可以到服务器中查看 service-discovery 服务的 Docker 日志进行确认;
docker logs --tail=500 servdiscovery
5. Jenkins
可以检测到微服务源码的变化,然后自动构建部署,从而以达到持续集成发布的目的呢?
一款轻量级开源的工具——Jenkins。
Jenkins 是一个用 Java 编写的开源的持续集成工具,它提供了软件开发的持续集成服务,可用于自动执行、构建、测试、交付或部署相关任务。Jenkins 可以执行基于 ApacheAnt 和 Apache Maven 所构建的项目,以及任意的 Shell 脚本和 Windows 批处理命令。
同时, Jenkins 也是一个高度可扩展的产品,提供了强大的插件生态环境,通过安装插件几乎能够满足任何你想要的构建任务。
11.4.1 安装 Jenkins
Jenkins 可以直接通过 Docker 安装、运行,也可以通过任何安装了 Java 运行时环境(JRE)的计算机独立运行。
如果通过 Docker 来运行 Jenkins 的话,在使用过程中会产生一些问题,一方面是由于 Jenkins 本身的配置问题,另外一方面是在构建任务时需要依赖。比如,当所构建的前端项目需要依赖 Node.js 时,就需要在容器内部安装 Node.js ,一旦容器出现问题需要移除,那么这些在容器内部安装的依赖就会丢失,需要再次进行安装。
下载官方提供的 WAR 包并将其存放到对应的目录下然后运行即可。
linux 下:
wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war
java -jar jenkins.war --httpPort=8080
运行后访问地址 http://servip:8080
11.4.2 Jenkins 配置
首先需要在 Jenkins 中配置 JDK 和 Maven 这两个工具。通过**“系统管理”|“全局工具配置”**命令进入配置界面;
Jenkins 中的全局工具提供了两种安装方式:一种是自动安装,通过指定名称和版本,Jenkins 会自动下载并安装,但安装 JDK 需要提供 Oracle 官网的账号及密码;另一种是自定义安装(在安装界面中取消勾选自动安装选项)
如果项目中还需要 Git、Gradle、Docker 等配置,可以自行完成。
此外,Jenkins 还提供了本身的自定义配置,如工作目录、邮件通知配置等,都可以在系统管理下看到相关配置。若需要进行权限控制,比如某个用户只能看到某些任务,Jenkins 也提供了完整的权限控制配置,在系统管理下的“管理用户”中就可以完成配置,配置步骤首先新建一个用户,然后转到“全局安全配置”页面进行权限分配。
Jenkins 权限配置主要是授权策略,可以根据不同的授权策略控制赋予用户权限,但这种配置方式略显复杂,可以使用 Role Strategy Plugin 插件简化配置。
6.总结
1:单体应用的困境,是现在普遍的困境。新的团队有了理念后,会在万丈高楼平地起时就采用该架构,避免单体应
用困境。
2:微服务是趋势,现在某些大型公司难以实现只是时间问题。除非它不需要拓展业务和更变业务。
3:18年前后 k8s 的出现,短短三年就被世界各互联网公司所接受和使用,就足以说明微服务的重要性。对运维人员和
开发人员来说,这是个大的挑战和机遇。
4:遇到风口,不进则退。
三、案例
1. 案例介绍
nginx 和 php-fpm 实现 php 网页正常运行。这个案例学通,之后就可以根据该案例知识,做更复杂的架构。该案例也是运维微服务需要基础掌握的核心内容。
2.问题解决
(1)一个容器只能有一个启动命令(CMD),但这里启动两个服务
(2)多个容器之间如何通信?
(3)php-fpm 只允许本机通信,多个容器通信需要怎么做?
(4)nginx 和 php-fpm 需要访问同一个网页文件,怎么解决?
2. Php-fpm 创建镜像准备
vim /etc/php-fpm.d/www.conf
listen = 0.0.0.0:9000
监听IP和端口。
;listen.allowed_clients = 127.0.0.1
允许连接的 FastCGI 客户端的 ipv4 地址列表。
mkdir /root/php-fpm
cp /etc/php-fpm.d/www.conf /root/php-fpm/
3. php-fpm 的 dockerfile
vim /root/php-fpm/dockerfile
FROM centos:7
RUN yum -y install php-fpm
EXPOSE 9000
COPY www.conf /etc/php-fpm.d/www.conf
CMD ["/usr/sbin/php-fpm","--nodaemonize"]
4. nginx 创建镜像准备
vim /etc/nginx/conf.d/default.conf
改成 php 配置
mkdir /root/nginx
cp /etc/nginx/conf.d/default.conf /root/nginx
mkdir /root/nginxweb
vim /root/nginxweb/index.php
<?php echo '<p>true</p>'; ?>
5. 写 nginx 的 dockerfile
vim /root/nginx/dockerfile
FROM centos:7
RUN rpm -Uvh
http://nginx.org/packages/centos/7/noarch/RPMS/
nginx-release-centos-7-0.el7.ngx.noarch.rpm
RUN yum -y install nginx
EXPOSE 80
CMD ["nginx","-g","daemon off;"]
6. 构建镜像
cd /root/nginx
docker build -t nginx:v1 .
cd /root/php-fpm
docker build -t php-fpm:v1
.
7. 启动容器
docker run -itd -p 8800:80 \
-v /root/nginxweb/:/usr/share/nginx/html/ \
--name nginx nginx:v1
docker run -itd --network=container:nginx \
-v /root/nginxweb/:/usr/share/nginx/html/ \
php-fpm:v1
8. 测试