前端技术
HTML
CSS
Javascript
前端框架和UI库
VUE
ReactJS
AngularJS
JQuery
NodeJS
JSON
Element-UI
Bootstrap
Material UI
服务端和客户端
Java
Python
PHP
Golang
Scala
Kotlin
Groovy
Ruby
Lua
.net
c#
c++
后端WEB和工程框架
SpringBoot
SpringCloud
Struts2
MyBatis
Hibernate
Tornado
Beego
Go-Spring
Go Gin
Go Iris
Dubbo
HessianRPC
Maven
Gradle
数据库
MySQL
Oracle
Mongo
中间件与web容器
Redis
MemCache
Etcd
Cassandra
Kafka
RabbitMQ
RocketMQ
ActiveMQ
Nacos
Consul
Tomcat
Nginx
Netty
大数据技术
Hive
Impala
ClickHouse
DorisDB
Greenplum
PostgreSQL
HBase
Kylin
Hadoop
Apache Pig
ZooKeeper
SeaTunnel
Sqoop
Datax
Flink
Spark
Mahout
数据搜索与日志
ElasticSearch
Apache Lucene
Apache Solr
Kibana
Logstash
数据可视化与OLAP
Apache Atlas
Superset
Saiku
Tesseract
系统与容器
Linux
Shell
Docker
Kubernetes
[Docker中自动创建本地挂载目录机制]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
Docker
在Docker容器中管理文件和目录是一项基础且重要的操作。随着容器化技术的日益成熟,不仅限于将文件夹放入容器,更涉及到数据持久化、卷管理和多容器间的数据共享等复杂场景。例如,Docker提供了-v或--volume选项用于创建数据卷,实现宿主机与容器之间的数据共享和持久化存储,即使容器被删除,数据依然得以保留。 近期,Docker推出了Compose V2版本,进一步简化了多容器应用程序的部署和管理,其中就包括对多个服务间共享文件夹的优化配置。通过在docker-compose.yml文件中定义volumes关键字,可以轻松指定不同服务间的文件夹挂载关系,这对于微服务架构中的日志共享、配置同步等需求提供了极大便利。 此外,Kubernetes作为容器编排领域的领导者,其PersistentVolume(PV)和PersistentVolumeClaim(PVC)机制为在Pod间共享文件夹提供了更为强大的解决方案。用户可以根据实际需求声明存储资源,实现跨节点甚至跨集群的数据共享。 深入理解并掌握这些高级功能,不仅可以确保在开发、测试到生产环境迁移过程中数据的一致性和完整性,更能提升容器化应用的可维护性和扩展性。对于持续关注云原生技术发展的开发者来说,不断跟进学习Docker及Kubernetes在数据管理方面的最新进展是十分必要的。
2023-11-22 11:10:48
520
键盘勇士
Docker
...天我们要聊的是如何在Docker上部署WGCLOUD的agent。好多小伙伴可能对这个概念还摸不着头脑,别急,我来带你们一步一步搞懂然后搞定它。装个监控工具(咱们叫它agent)可能听着挺麻烦,但实际上它就是个帮手,能让我们更轻松地照顾好服务器。废话不多说,让我们开始吧! 2. Docker基础 首先,我们需要确保你已经安装了Docker,并且对它有一定的了解。如果你是第一次用Docker,可以把它想象成一个轻量级的“虚拟房间”,在这个房间里,你可以跑你的应用,完全不用操心那些烦人的环境配置问题。就像你搬进一个新的公寓,不需要重新装修或买新家具,直接就可以住进去一样方便。 bash 检查Docker是否已安装 docker --version 安装Docker(以Ubuntu为例) sudo apt-get update sudo apt-get install docker.io 3. 获取WGCLOUD的agent镜像 接下来,我们需要获取WGCLOUD的agent镜像。这可以通过Docker Hub来完成。Docker Hub就像是一个大超市,里面摆满了各种Docker镜像,你想找啥都有,真是太方便了! bash 拉取WGCLOUD的agent镜像 docker pull wgc/wgcloud-agent:latest 4. 创建Docker容器 现在我们已经有了镜像,下一步就是创建一个Docker容器来运行这个agent。我们可以使用docker run命令来完成这个操作。在这过程中,你可能得设定一些东西,比如说容器的名称啊,端口映射之类的。 bash 创建并启动Docker容器 docker run -d --name wgcloud-agent \ -p 8080:8080 \ -v /path/to/config:/config \ wgc/wgcloud-agent:latest 这里,-d表示后台运行,--name用来指定容器的名字,-p用于映射端口,-v则用于挂载卷,将宿主机上的某个目录挂载到容器内的某个目录。/path/to/config是你本地的配置文件路径,你需要根据实际情况修改。 5. 配置WGCLOUD的agent 配置文件是WGCLOUD agent运行的关键,它包含了agent的一些基本设置,如服务器地址、认证信息等。我们需要将这些信息正确地配置到文件中。 yaml 示例配置文件 server: url: "http://your-server-address" auth_token: "your-auth-token" 将上述内容保存为config.yaml文件,并按照上面的步骤挂载到容器内。 6. 启动与验证 一切准备就绪后,我们就可以启动容器了。启动后,你可以通过访问http://localhost:8080来验证agent是否正常工作。如果一切顺利,你应该能看到一些监控数据。 bash 查看容器日志 docker logs wgcloud-agent 如果日志中没有错误信息,恭喜你,你的agent已经成功部署并运行了! 7. 总结 好了,到这里我们的教程就结束了。跟着这个教程,你不仅搞定了在Docker上部署WGCLOUD代理的事儿,还顺带学会了几个玩转Docker的小技巧。如果你有任何疑问或者遇到任何问题,欢迎随时联系我。我们一起学习,一起进步! --- 希望这篇教程对你有所帮助,如果你觉得这篇文章有用,不妨分享给更多的人。最后,记得给我点个赞哦!
2025-03-09 16:19:42
87
青春印记_
转载文章
...的操作系统库或工具、创建用户、创建运行目录、解压、设置文件权限等等),这么做的好处是把应用及其依赖封装到了一个相对封闭的环境,减少了应用对外部环境的依赖,增强了应用在各种不同环境下的行为一致性,同时也减少了应用部署时间。 镜像分层:容器镜像包是分层结构,同一个主机上的镜像层是可以在多个容器之间共享的,这个机制可以极大减少镜像更新时候拉取镜像包的时间,通常应用程序更新升级都只是更新业务层(如Java程序的jar包),而镜像中的操作系统Lib层、运行时(如Jre)层等文件不会频繁更新。因此新版本镜像实质有变化的只有很小的一部分,在更新升级时候也只会从镜像仓库拉取很小的文件,所以速度很快。 应用资源调度:资源(计算/存储/网络)都是以应用为中心的,中心体现在资源分配是按照应用粒度分配资源、资源随应用迁移。 基于上述容器技术特点,可以推导出容器技术的3大使用场景:CI/CD、提升资源利用率、弹性伸缩。这3个使用场景自然推导出通用的商业层面收益:CI/CD提升研发效率、提升资源利用率降低成本、按需弹性伸缩在体验与成本之间达成平衡。 当然,除了商业目标之外,可能还有其他一些考虑因素,如基于容器技术实现计算任务调度平台、保持团队技术先进性等。 CI/CD提升研发效率 为什么容器技术适合CI/CD CI/CD是DevOps的关键组成部分,DevOps是一套软件工程的流程,用于持续提升软件开发效率与软件交付质量。DevOps流程来源于制造业的精益生产理念,在这个领域的领头羊是丰田公司,《丰田套路》这本书总结丰田公司如何通过PDCA(Plan-Do-Check-Act)方法实施持续改进。PDCA通常也称为PDCA循环,PDCA实施过程简要描述为:确定目标状态、分析当前状态、找出与目标状态的差距、制定实施计划、实施并总结、开始下一个PDCA过程。 DevOps基本也是这么一个PDCA流程循环,很容易认知到PDCA过程中效率是关键,同一时间段内,实施更多数量的PDCA过程,收益越高。在软件开发领域的DevOps流程中,各种等待(等待编译、等待打包、等待部署等)、各种中断(部署失败、机器故障)是影响DevOps流程效率的重要因素。 容器技术出来之后,将容器技术应用到DevOps场景下,可以从技术手段消除DevOps流程中的部分等待与中断,从而大幅度提升DevOps流程中CI/CD的效率。 容器的OCI标准定义了容器镜像规范,容器镜像包与传统的压缩包(zip/tgz等)相比有两个关键区别点:1)分层存储;2)打包即部署。 分层存储可以极大减少镜像更新时候拉取镜像包的时间,通常应用程序更新升级都只是更新业务层(如Java程序的jar包),而镜像中的操作系统Lib层、运行时(如Jre)层等文件不会频繁更新。因此新版本镜像实质有变化的只有很小的一部分,在更新升级时候也只会从镜像仓库拉取很小的文件,所以速度很快。 打包即部署是指在容器镜像制作过程包含了传统软件包部署的过程(安装依赖的操作系统库或工具、创建用户、创建运行目录、解压、设置文件权限等等),这么做的好处是把应用及其依赖封装到了一个相对封闭的环境,减少了应用对外部环境的依赖,增强了应用在各种不同环境下的行为一致性,同时也减少了应用部署时间。 基于容器镜像的这些优势,容器镜像用到CI/CD场景下,可以减少CI/CD过程中的等待时间,减少因环境差异而导致的部署中断,从而提升CI/CD的效率,提升整体研发效率。 CI/CD的关键诉求与挑战 快 开发人员本地开发调试完成后,提交代码,执行构建与部署,等待部署完成后验证功能。这个等待的过程尽可能短,否则开发人员工作容易被打断,造成后果就是效率降低。如果提交代码后几秒钟就能够完成部署,那么开发人员几乎不用等待,工作也不会被打断;如果需要好几分钟或十几分钟,那么可以想象,这十几分钟就是浪费了,这时候很容易做点别的事情,那么思路又被打断了。 所以构建CI/CD环境时候,快是第一个需要考虑的因素。要达到快,除了有足够的机器资源免除排队等待,引入并行编译技术也是常用做法,如Maven3支持多核并行构建。 自定义流程 不同行业存在不同的行业规范、监管要求,各个企业有一套内部质量规范,这些要求都对软件交付流程有定制需求,如要求使用商用的代码扫描工具做安全扫描,如构建结果与企业内部通信系统对接发送消息。 在团队协同方面,不同的公司,对DevOps流程在不同团队之间分工有差异,典型的有开发者负责代码编写构建出构建物(如jar包),而部署模板、配置由运维人员负责;有的企业开发人员负责构建并部署到测试环境;有的企业开发人员直接可以部署到生产环境。这些不同的场景,对CI/CD的流程、权限管控都有定制需求。 提升资源利用率 OCI标准包含容器镜像标准与容器运行时标准两部分,容器运行时标准聚焦在定义如何将镜像包从镜像仓库拉取到本地并更新、如何隔离运行时资源这些方面。得益于分层存储与打包即部署的特性,容器镜像从到镜像仓库拉取到本地运行速度非常快(通常小于30秒,依赖镜像本身大小等因素),基于此可以实现按需分配容器运行时资源(cpu与内存),并限定单个容器资源用量;然后根据容器进程资源使用率设定弹性伸缩规则,实现自动的弹性伸缩。 这种方式相对于传统的按峰值配置资源方式,可以提升资源利用率。 按需弹性伸缩在体验与成本之间达成平衡 联动弹性伸缩 应用运行到容器,按需分配资源之后,理想情况下,Kubernetes的池子里没有空闲的资源。这时候扩容应用实例数,新扩容的实例会因资源不足调度失败。这时候需要资源池能自动扩容,加入新的虚拟机,调度新扩容的应用。 由于应用对资源的配比与Flavor有要求,因此新加入的虚拟机,应当是与应用所需要的资源配比与Flavor一致的。缩容也是类似。 弹性伸缩还有一个诉求点是“平滑”,对业务做到不感知,也称为“优雅”扩容/缩容。 请求风暴 上面提到的弹性伸缩一般是有计划或缓慢增压的场景,存在另外一种无法预期的请求风暴场景,这种场景的特征是无法预测、突然请求量增大数倍或数十倍、持续时间短。典型的例子如行情交易系统,当行情突变的时候,用户访问量徒增,持续几十分钟或一个小时。 这种场景的弹性诉求,要求短时间内能将资源池扩大数倍,关键是速度要快(秒级),否则会来不及扩容,系统已经被冲垮(如果无限流的话)。 目前基于 Virtual Kubelet 与云厂家的 Serverless 容器,理论上可以提供应对请求风暴的方案。不过在具体实施时候,需要考虑传统托管式Kubernetes容器管理平台与Serverless容器之间互通的问题,需要基于具体厂家提供的能力来评估。 基于容器技术实现计算调度平台 计算(大数据/AI训练等)场景的特征是短时间内需要大量算力,算完即释放。容器的环境一致性以及调度便利性适合这种场景。 技术选型 容器技术是属于基础设施范围,但是与传统虚拟化技术(Xen/KVM)比较,容器技术是应用虚拟化,不是纯粹的资源虚拟化,与传统虚拟化存在差异。在容器技术选型时候,需要结合当前团队在应用管理与资源管理的现状,对照容器技术与虚拟化技术的差异,选择最合适的容器技术栈。 什么是容器技术 (1)容器是一种轻量化的应用虚拟化技术。 在讨论具体的容器技术栈的时候,先介绍目前几种常用的应用虚拟化技术,当前有3种主流的应用虚拟化技术: LXC,MicroVM,UniKernel(LibOS)。 LXC: Linux Container,通过 Linux的 namespace/cgroups/chroot 等技术隔离进程资源,目前应用最广的docker就是基于LXC实现应用虚拟化的。 MicroVM: MicroVM 介于 传统的VM 与 LXC之间,隔离性比LXC好,但是比传统的VM要轻量,轻量体现在体积小(几M到几十M)、启动快(小于1s)。 AWS Firecracker 就是一种MicroVM的实现,用于AWS的Serverless计算领域,Serverless要求启动快,租户之间隔离性好。 UniKernel: 是一种专用的(特定编程语言技术栈专用)、单地址空间、使用 library OS 构建出来的镜像。UniKernel要解决的问题是减少应用软件的技术栈层次,现代软件层次太多导致越来越臃肿:硬件+HostOS+虚拟化模拟+GuestOS+APP。UniKernel目标是:硬件+HostOS+虚拟化模拟+APP-with-libos。 三种技术对比表: 开销 体积 启动速度 隔离/安全 生态 LXC 低(几乎为0) 小 快(等同进程启动) 差(内核共享) 好 MicroVM 高 大 慢(小于1s) 好 中(Kata项目) UniKernel 中 中 中 好 差 根据上述对比来看,LXC是应用虚拟化首选的技术,如果LXC无法满足隔离性要,则可以考虑MicroVM这种技术。当前社区已经在着手融合LXC与MicroVM这两种技术,从应用打包/发布调度/运行层面统一规范,Kubernetes集成Kata支持混合应用调度特性可以了解一下。 UniKernel 在应用生态方面相对比较落后,目前在追赶中,目前通过 linuxkit 工具可以在UniKernel应用镜像中使用docker镜像。这种方式笔者还未验证过,另外docker镜像运行起来之后,如何监控目前还未知。 从上述三种应用虚拟化技术对比,可以得出结论: (2)容器技术与传统虚拟化技术不断融合中。 再从规范视角来看容器技术,可以将容器技术定义为: (3)容器=OCI+CRI+辅助工具。 OCI规范包含两部分,镜像规范与运行时规范。简要的说,要实现一个OCI的规范,需要能够下载镜像并解压镜像到文件系统上组成成一个文件目录结构,运行时工具能够理解这个目录结构并基于此目录结构管理(创建/启动/停止/删除)进程。 容器(container)的技术构成就是实现OCI规范的技术集合。 对于不同的操作系统(Linux/Windows),OCI规范的实现技术不同,当前docker的实现,支持Windows与Linux与MacOS操作系统。当前使用最广的是Linux系统,OCI的实现,在Linux上组成容器的主要技术: chroot: 通过分层文件系统堆叠出容器进程的rootfs,然后通过chroot设置容器进程的根文件系统为堆叠出的rootfs。 cgroups: 通过cgroups技术隔离容器进程的cpu/内存资源。 namesapce: 通过pid, uts, mount, network, user namesapce 分别隔离容器进程的进程ID,时间,文件系统挂载,网络,用户资源。 网络虚拟化: 容器进程被放置到独立的网络命名空间,通过Linux网络虚拟化veth, macvlan, bridge等技术连接主机网络与容器虚拟网络。 存储驱动: 本地文件系统,使用容器镜像分层文件堆叠的各种实现驱动,当前推荐的是overlay2。 广义的容器还包含容器编排,即当下很火热的Kubernetes。Kubernetes为了把控容器调度的生态,发布了CRI规范,通过CRI规范解耦Kubelet与容器,只要实现了CRI接口,都可以与Kubelet交互,从而被Kubernetes调度。OCI规范的容器实现与CRI标准接口对接的实现是CRI-O。 辅助工具用户构建镜像,验证镜像签名,管理存储卷等。 容器定义 容器是一种轻量化的应用虚拟化技术。 容器=OCI+CRI+辅助工具。 容器技术与传统虚拟化技术不断融合中。 什么是容器编排与调度 选择了应用虚拟化技术之后,还需要应用调度编排,当前Kubernetes是容器领域内编排的事实标准,不管使用何种应用虚拟化技术,都已经纳入到了Kubernetes治理框架中。 Kubernetes 通过 CRI 接口规范,将应用编排与应用虚拟化实现解耦:不管使用何种应用虚拟化技术(LXC, MicroVM, LibOS),都能够通过Kubernetes统一编排。 当前使用最多的是docker,其次是cri-o。docker与crio结合kata-runtime都能够支持多种应用虚拟化技术混合编排的场景,如LXC与MicroVM混合编排。 docker(now): Moby 公司贡献的 docker 相关部件,当前主流使用的模式。 docker(daemon) 提供对外访问的API与CLI(docker client) containerd 提供与 kubelet 对接的 CRI 接口实现 shim负责将Pod桥接到Host namespace。 cri-o: 由 RedHat/Intel/SUSE/IBM/Hyper 公司贡献的实现了CRI接口的符合OCI规范的运行时,当前包括 runc 与 kata-runtime ,也就是说使用 cir-o 可以同时运行LXC容器与MicroVM容器,具体在Kata介绍中有详细说明。 CRI-O: 实现了CRI接口的进程,与 kubelet 交互 crictl: 类似 docker 的命令行工具 conmon: Pod监控进程 other cri runtimes: 其他的一些cri实现,目前没有大规模应用到生产环境。 容器与传统虚拟化差异 容器(container)的技术构成 前面主要讲到的是容器与编排,包括CRI接口的各种实现,我们把容器领域的规范归纳为南向与北向两部分,CRI属于北向接口规范,对接编排系统,OCI就属于南向接口规范,实现应用虚拟化。 简单来讲,可以这么定义容器: 容器(container) ~= 应用打包(build) + 应用分发(ship) + 应用运行/资源隔离(run)。 build-ship-run 的内容都被定义到了OCI规范中,因此也可以这么定义容器: 容器(container) == OCI规范 OCI规范包含两部分,镜像规范与运行时规范。简要的说,要实现一个OCI的规范,需要能够下载镜像并解压镜像到文件系统上组成成一个文件目录结构,运行时工具能够理解这个目录结构并基于此目录结构管理(创建/启动/停止/删除)进程。 容器(container)的技术构成就是实现OCI规范的技术集合。 对于不同的操作系统(Linux/Windows),OCI规范的实现技术不同,当前docker的实现,支持Windows与Linux与MacOS操作系统。当前使用最广的是Linux系统,OCI的实现,在Linux上组成容器的主要技术: chroot: 通过分层文件系统堆叠出容器进程的rootfs,然后通过chroot设置容器进程的根文件系统为堆叠出的rootfs。 cgroups: 通过cgroups技术隔离容器进程的cpu/内存资源。 namesapce: 通过pid, uts, mount, network, user namesapce 分别隔离容器进程的进程ID,时间,文件系统挂载,网络,用户资源。 网络虚拟化: 容器进程被放置到独立的网络命名空间,通过Linux网络虚拟化veth, macvlan, bridge等技术连接主机网络与容器虚拟网络。 存储驱动: 本地文件系统,使用容器镜像分层文件堆叠的各种实现驱动,当前推荐的是overlay2。 广义的容器还包含容器编排,即当下很火热的Kubernetes。Kubernetes为了把控容器调度的生态,发布了CRI规范,通过CRI规范解耦Kubelet与容器,只要实现了CRI接口,都可以与Kubelet交互,从而被Kubernetes调度。OCI规范的容器实现与CRI标准接口对接的实现是CRI-O。 容器与虚拟机差异对比 容器与虚拟机的差异可以总结为2点:应用打包与分发的差异,应用资源隔离的差异。当然,导致这两点差异的根基是容器是以应用为中心来设计的,而虚拟化是以资源为中心来设计的,本文对比容器与虚拟机的差异,更多的是站在应用视角来对比。 从3个方面对比差异:资源隔离,应用打包与分发,延伸的日志/监控/DFX差异。 1.资源隔离 隔离机制差异 容器 虚拟化 mem/cpu cgroup, 使用时候设定 require 与 limit 值 QEMU, KVM network Linux网络虚拟化技术(veth,tap,bridge,macvlan,ipvlan), 跨虚拟机或出公网访问:SNAT/DNAT, service转发:iptables/ipvs, SR-IOV Linux网络虚拟化技术(veth,tap,bridge,macvlan,ipvlan), QEMU, SR-IOV storage 本地存储: 容器存储驱动 本地存储:virtio-blk 差异引入问题与实践建议 应用程序未适配 cgroup 的内存隔离导致问题: 典型的是 JVM 虚拟机,在 JVM 启动时候会根据系统内存自动设置 MaxHeapSize 值,通常是系统内存的1/4,但是 JVM 并未考虑 cgroup 场景,读系统内存时候任然读取主机的内存来设置 MaxHeapSize,这样会导致内存超过 cgroup 限制从而导致进程被 kill 。问题详细阐述与解决建议参考Java inside docker: What you must know to not FAIL。 多次网络虚拟化问题: 如果在虚拟机内使用容器,会多一层网络虚拟化,并加入了SNAT/DNAT技术, iptables/ipvs技术,对网络吞吐量与时延都有影响(具体依赖容器网络方案),对问题定位复杂度变高,同时还需要注意网络内核参数调优。 典型的网络调优参数有:转发表大小 /proc/sys/net/netfilter/nf_conntrack_max 使用iptables 作为service转发实现的时候,在转发规则较多的时候,iptables更新由于需要全量更新导致非常耗时,建议使用ipvs。详细参考[华为云在 K8S 大规模场景下的 Service 性能优化实践](https://zhuanlan.zhihu.com/p/37230013)。 容器IP地址频繁变化不固定,周边系统需要协调适配,包括基于IP地址的白名单或防火墙控制策略需要调整,CMDB记录的应用IP地址需要适配动态IP或者使用服务名替代IP地址。 存储驱动带来的性能损耗: 容器本地文件系统是通过联合文件系统方式堆叠出来的,当前主推与默认提供的是overlay2驱动,这种模式应用写本地文件系统文件或修改已有文件,使用Copy-On-Write方式,也就是会先拷贝源文件到可写层然后修改,如果这种操作非常频繁,建议使用 volume 方式。 2.应用打包与分发 应用打包/分发/调度差异 容器 虚拟化 打包 打包既部署 一般不会把应用程序与虚拟机打包在一起,通过部署系统部署应用 分发 使用镜像仓库存储与分发 使用文件存储 调度运行 使用K8S亲和/反亲和调度策略 使用部署系统的调度能力 差异引入问题与实践建议 部署提前到构建阶段,应用需要支持动态配置与静态程序分离;如果在传统部署脚本中依赖外部动态配置,这部分需要做一些调整。 打包格式发生变化,制作容器镜像需要注意安全/效率因素,可参考Dockerfile最佳实践 容器镜像存储与分发是按layer来组织的,镜像在传输过程中放篡改的方式是传统软件包有差异。 3.监控/日志/DFX 差异 容器 虚拟化 监控 cpu/mem的资源上限是cgroup定义的;containerd/shim/docker-daemon等进程的监控 传统进程监控 日志采集 stdout/stderr日志采集方式变化;日志持久化需要挂载到volume;进程会被随机调度到其他节点导致日志需要实时采集否则分散很难定位 传统日志采集 问题定位 进程down之后自动拉起会导致问题定位现场丢失;无法停止进程来定位问题因为停止即删除实例 传统问题定位手段 差异引入问题实践与建议 使用成熟的监控工具,运行在docker中的应用使用cadvisor+prometheus实现采集与警报,cadvisor中预置了常用的监控指标项 对于docker管理进程(containerd/shim/docker-daemon)也需要一并监控 使用成熟的日志采集工具,如果已有日志采集Agent,则可以考虑将日志文件挂载到volume后由Agent采集;需要注意的是stderr/stdout输出也要一并采集 如果希望容器内应用进程退出后保留现场定位问题,则可以将Pod的restartPolicy设置为never,进程退出后进程文件都还保留着(/var/lib/docker/containers)。但是这么做的话需要进程没有及时恢复,会影响业务,需要自己实现进程重拉起。 团队配合 与周边的开发团队、架构团队、测试团队、运维团队评审并交流方案,与周边团队达成一致。 落地策略与注意事项 逐步演进过程中网络互通 根据当前已经存在的基础实施情况,选择容器化落地策略。通常使用逐步演进的方式,由于容器化引入了独立的网络namespace导致容器与传统虚拟机进程网络隔离,逐步演进过程中如何打通隔离的网络是最大的挑战。 分两种场景讨论: 不同服务集群之间使用VIP模式互通: 这种模式相对简单,基于VIP做灰度发布。 不同服务集群之间使用微服务点对点模式互通(SpringCloud/ServiceComb/Dubbo都是这一类): 这种模式相对复杂,在逐步容器化过程中,要求容器网络与传统虚拟机网络能够互通(难点是在虚拟机进程内能够直接访问到容器网络的IP地址),当前解决这个问题有几种方法。 自建Kubernetes场景,可使用开源的kube-router,kube-router 使用BGP协议实现容器网络与传统虚拟机网络之间互通,要求网络交换机支持BGP协议。 使用云厂商托管Kubernetes场景,选择云厂商提供的VPC-Router互通的网络插件,如阿里云的Terway网络插件, 华为云的Underlay网络模式。 选择物理机还是虚拟机 选择物理机运行容器还是虚拟机运行容器,需要结合基础设施与业务隔离性要求综合考虑。分两种场景:自建IDC、租用公有云。 自建IDC: 理想情况是使用物理机组成一个大集群,根据业务诉求,对资源保障与安全性要求高的应用,使用MicorVM方式隔离;普通应用使用LXC方式隔离。所有物理机在一个大集群内,方便削峰填谷提升资源利用率。 租用公有云:当前公有云厂家提供的裸金属服务价格较贵且只能包周期,使用裸金属性价比并不高,使用虚拟机更合适。 集群规模与划分 选择集群时候,是多个应用共用一个大集群,还是按应用分组分成多个小集群呢?我们把节点规模数量>=1000的定义为大集群,节点数<1000的定义为小集群。 大集群的优点是资源池共享容器,方便资源调度(削峰填谷);缺点是随着节点数量与负载数量的增多,会引入管理性能问题(需要量化): DNS 解析表变大,增加/删除 Service 或 增加/删除 Endpoint 导致DNS表刷新慢 K8S Service 转发表变大,导致工作负载增加/删除刷新iptables/ipvs记录变慢 etcd 存储空间变大,如果加上ConfigMap,可能导致 etcd 访问时延增加 小集群的优点是不会有管理性能问题,缺点是会导致资源碎片化,不容易共享。共享分两种情况: 应用之间削峰填谷:目前无法实现 计算任务与应用之间削峰填谷:由于计算任务是短时任务,可以通过上层的任务调度软件,在多个集群之间分发计算任务,从而达到集群之间资源共享的目的。 选择集群规模的时候,可以参考上述分析,结合实际情况选择适合的集群划分。 Helm? Helm是为了解决K8S管理对象散碎的问题,在K8S中并没有"应用"的概念,只有一个个散的对象(Deployment, ConfigMap, Service, etc),而一个"应用"是多个对象组合起来的,且这些对象之间还可能存在一定的版本配套关系。 Helm 通过将K8S多个对象打包为一个包并标注版本号形成一个"应用",通过 Helm 管理进程部署/升级这个"应用"。这种方式解决了一些问题(应用分发更方便)同时也引入了一些问题(引入Helm增加应用发布/管理复杂度、在K8S修改了对象后如何同步到Helm)。对于是否需要使用Helm,建议如下: 在自运维模式下不使用Helm: 自运维模式下,很多场景是开发团队交付一个运行包,运维团队负责部署与配置下发,内部通过兼容性或软件包与配置版本配套清单、管理软件包与配置的配套关系。 在交付软件包模式下使用Helm: 交付软件包模式下,Helm 这种把散碎组件组装为一个应用的模式比较适合,使用Helm实现软件包分发/部署/升级场比较简单。 Reference DOCKER vs LXC vs VIRTUAL MACHINES Cgroup与LXC简介 Introducing Container Runtime Interface (CRI) in Kubernetes frakti rkt appc-spec OCI 和 runc:容器标准化和 docker Linux 容器技术史话:从 chroot 到未来 Linux Namespace和Cgroup Java inside docker: What you must know to not FAIL QEMU,KVM及QEMU-KVM介绍 kvm libvirt qemu实践系列(一)-kvm介绍 KVM 介绍(4):I/O 设备直接分配和 SR-IOV [KVM PCI/PCIe Pass-Through SR-IOV] prometheus-book 到底什么是Unikernel? The Rise and Fall of the Operating System The Design and Implementation of the Anykernel and Rump Kernels UniKernel Unikernel:从不入门到入门 OSv 京东如何打造K8s全球最大集群支撑万亿电商交易 Cloud Native App Hub 更多云最佳实践 https://best.practices.cloud 本篇文章为转载内容。原文链接:https://blog.csdn.net/sinat_33155975/article/details/118013855。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-09-17 15:03:28
225
转载
Docker
在利用Docker的期间,数据路径是至关重要的。Docker是利用映像的方式构建容器,容器中的数据也需要存储在本地,因此Docker的数据管控是依赖于存储卷(Volume)和存储卷容器(Volume Container)达成的。 存储卷是Docker提供的一种方式,可以将本地宿主机的目录及文件装载到容器内部。存储卷可以保证容器中的数据持久保存,且容器的数据可以在不同的容器之间分享。比如,下面的命令将本地目录 /data 装载到容器内部的 /app 目录: docker run -v /data:/app image_name 利用这种方式,容器中的数据发生变化时,本地宿主机的数据也会随之更新,也可以通过修改本地宿主机上的文件来修改容器中的文件。 存储卷容器是一种特殊的容器,用于管理存储卷。存储卷容器与存储卷的关系就像是一个储藏室和一个存储空间的关系。存储卷容器负责构建存储卷和管理存储卷的生命周期,而其他容器可以通过装载存储卷容器来利用存储卷。比如,下面的命令构建一个名为 my_data 的存储卷容器: docker create -v /app --name my_data busybox 利用这种方式,可以通过装载 my_data 存储卷容器来利用存储卷,比如: docker run --volumes-from my_data image_name 在利用存储卷的期间,还有一些需要注意的细节。首先,不同的容器中装载的存储卷是相互隔离的,因此不同的容器不能利用相同的目录装载存储卷;其次,利用 -v 参数构建容器时,如果本地目录不存在,则会自动构建;最后,存储卷的更新和删除需要手动执行,否则存储卷和容器中的数据将一直存在。
2023-10-29 12:32:53
504
软件工程师
Docker
在运用Docker的时候,我们可能会碰到因为一些因素致使信息遗失的情况,这时我们需要对Docker数据进行找回。下面我们将从几个方面介绍数据找回的方法。 1. 利用实例存档文件 1. 先在需要找回数据的主机上终止所有有关实例。 2. 根据主机上已有实例的存档文件进行新建新的实例。 3. 在新实例里将数据目录映射到本地,运用 scp 命令将备份数据复制到数据目录中。 4. 通过启动新的实例并挂载数据目录的方式实现数据找回。 2. 利用数据卷备份 1. 在需要备份的数据卷所在的实例内,运用 tar 命令将数据卷的所有目录和文件备份为一个文件。 2. 将存档文件传输到安全的存储介质上,例如 NAS 服务器中。 3. 在发生信息遗失的情况下,从备份介质中找回存档文件。 4. 利用 docker volume create 命令创建一个新的数据卷,并挂载到实例中。 5. 利用 tar 命令将存档文件中的数据找回到新的数据卷中。 6. 挂载新的数据卷到有关实例中实现数据找回。 总之,在日常运用 Docker 时,一定要注意备份好数据,保护好自己的数据。
2023-04-14 09:42:03
301
码农
Docker
Docker , Docker是一款开源的应用容器引擎,通过容器化技术,它可以将应用程序及其依赖环境打包成一个可移植、轻量级的容器,使得应用在开发、测试和生产环境中能够实现快速部署、一致运行,并且资源隔离性良好。在本文中,Docker被强调为一种标准化的管理工具,通过创建和使用Docker镜像以及编写Dockerfile来简化应用程序生命周期的管理。 容器化技术 , 容器化技术是一种操作系统级别的虚拟化方法,它能够在单一操作系统内核上运行多个独立的、隔离的应用程序实例(称为容器)。每个容器都拥有自己独立的文件系统、网络配置、进程空间等资源,从而确保应用的部署不受底层基础设施差异的影响。在文中,Docker作为容器化技术的典型代表,实现了应用程序及其依赖项的一致性和可移植性。 Dockerfile , Dockerfile是一个文本文件,其中包含了用户自定义的用于构建Docker镜像的一系列指令。在Docker中,开发者通过编写Dockerfile来详细描述如何从基础镜像开始逐步构建目标容器镜像的过程,包括安装软件包、设置环境变量、复制文件、暴露端口等操作。在文章给出的示例中,Dockerfile指定了使用的父镜像、容器启动时执行的命令、工作目录、挂载本地文件夹以及安装应用所需依赖等步骤,是构建Docker容器镜像的关键蓝图。
2023-01-30 11:42:25
445
数据库专家
转载文章
... 快速参考 维护者:Docker 社区和 MySQL 团队 从哪里获得帮助:Docker 社区论坛、Docker 社区 Slack 或 Stack Overflow 2.2. 支持的标签和各自的 Dockerfile 链接 8.0.28, 8.0, 8, latest 5.7.37, 5.7, 5 2.3. 快速参考(续) 在哪里提交问题:https://github.com/docker-library/mysql/issues 支持的架构:(更多信息)amd64 发布的镜像工件详情:repo-info repo 的 repos/mysql/ 目录(历史)(镜像元数据、传输大小等) 镜像更新:official-images repo 的 library/mysql 标签 官方图像 repo 的库/mysql 文件(历史) 此描述的来源:docs repo 的 mysql/ 目录(历史) 2.4. 如何使用镜像 2.4.1. 启动一个mysql服务器实例 启动 MySQL 实例很简单: $ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag 其中 some-mysql 是您要分配给容器的名称, my-secret-pw 是要为 MySQL root 用户设置的密码,而 tag 是指定您想要的 MySQL 版本的标签。 有关相关标签,请参见上面的列表。 以下是示例(通常要设置时区),注意-v 这里是挂载磁盘,请提前创建目录/var/mysql/data,/var/lib/mysql是容器里的原持久化目录: docker run --name mysql202201 -e MYSQL_ROOT_PASSWORD=123456 -e TZ=Asia/Shanghai -v /var/mysql/data:/var/lib/mysql -d mysql:5.7 2.4.2. 从 MySQL 命令行客户端连接到 MySQL 以下命令启动另一个 mysql 容器实例并针对您的原始 mysql 容器运行 mysql 命令行客户端,允许您针对您的数据库实例执行 SQL 语句: $ docker run -it --network some-network --rm mysql mysql -hsome-mysql -uexample-user -p 其中 some-mysql 是原始 mysql 容器的名称(连接到 some-network Docker 网络)。 此镜像也可以用作非 Docker 或远程实例的客户端: $ docker run -it --rm mysql mysql -hsome.mysql.host -usome-mysql-user -p 有关 MySQL 命令行客户端的更多信息,请参阅 MySQL 文档。 2.4.3. 容器外访问和查看 MySQL 日志 docker exec 命令允许您在 Docker 容器内运行命令。 以下命令行将为您提供 mysql 容器内的 bash shell: $ docker exec -it some-mysql bash 第一次启动一个MySQL容器后,需要对账户进行授权,否则无法远程访问,请先使用上面的命令进入容器内,然后使用以下命令连接到mysql服务: mysql -uroot -p 输入密码回车,进入mysql命令界面mysql> 接着授权root远程访问权限: mysql> GRANT ALL PRIVILEGES ON . TO 'root'@'%' IDENTIFIED BY '123456'; 然后就可以远程用MySQL客户端连接到MySQL容器了。 日志可通过 Docker 的容器日志获得: $ docker logs some-mysql 2.4.4. 使用自定义 MySQL 配置文件 MySQL 的默认配置可以在 /etc/mysql/my.cnf 中找到,其中可能包含额外的目录,例如 /etc/mysql/conf.d 或 /etc/mysql/mysql.conf.d。 请检查 mysql 映像本身中的相关文件和目录以获取更多详细信息。 如果 /my/custom/config-file.cnf 是你的自定义配置文件的路径和名称,你可以这样启动你的 mysql 容器(注意这个命令只使用了自定义配置文件的目录路径): $ docker run --name some-mysql -v /my/custom:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag 这将启动一个新容器 some-mysql,其中 MySQL 实例使用来自 /etc/mysql/my.cnf 和 /etc/mysql/conf.d/config-file.cnf 的组合启动设置,后者的设置优先 . 没有 cnf 文件的配置 许多配置选项可以作为标志传递给 mysqld。 这将使您可以灵活地自定义容器,而无需 cnf 文件。 例如,如果要将所有表的默认编码和排序规则更改为使用 UTF-8 (utf8mb4),只需运行以下命令: $ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci 如果您想查看可用选项的完整列表,只需运行: $ docker run -it --rm mysql:tag --verbose --help 2.4.5. 环境变量 启动 mysql 镜像时,可以通过在 docker run 命令行中传递一个或多个环境变量来调整 MySQL 实例的配置。 请注意,如果您使用已包含数据库的数据目录启动容器,则以下任何变量都不会产生任何影响:任何预先存在的数据库在容器启动时将始终保持不变。 另请参阅 https://dev.mysql.com/doc/refman/5.7/en/environment-variables.html 以获取 MySQL 的环境变量的文档(尤其是 MYSQL_HOST 等变量,已知与此镜像一起使用时会导致问题)。 MYSQL_ROOT_PASSWORD 此变量是必需的,并指定将为 MySQL root 超级用户帐户设置的密码。 在上面的示例中,它被设置为 my-secret-pw。 MYSQL_DATABASE 此变量是可选的,允许您指定要在映像启动时创建的数据库的名称。 如果提供了用户/密码(见下文),则该用户将被授予对此数据库的超级用户访问权限(对应于 GRANT ALL)。 MYSQL_USER、MYSQL_PASSWORD 这些变量是可选的,用于创建新用户和设置该用户的密码。 该用户将被授予对 MYSQL_DATABASE 变量指定的数据库的超级用户权限(见上文)。 要创建用户,这两个变量都是必需的。 请注意,不需要使用此机制来创建超级用户超级用户,默认情况下会使用 MYSQL_ROOT_PASSWORD 变量指定的密码创建该用户。 MYSQL_ALLOW_EMPTY_PASSWORD 这是一个可选变量。 设置为非空值,例如 yes,以允许使用 root 用户的空白密码启动容器。 注意:除非您真的知道自己在做什么,否则不建议将此变量设置为 yes,因为这将使您的 MySQL 实例完全不受保护,从而允许任何人获得完全的超级用户访问权限。 MYSQL_RANDOM_ROOT_PASSWORD 这是一个可选变量。 设置为非空值,如 yes,为 root 用户生成随机初始密码(使用 pwgen)。 生成的根密码将打印到标准输出(生成的根密码:…)。 MYSQL_ONETIME_PASSWORD 一旦初始化完成,将 root(不是 MYSQL_USER 中指定的用户!)用户设置为过期,强制在第一次登录时更改密码。 任何非空值都将激活此设置。 注意:此功能仅在 MySQL 5.6+ 上受支持。 在 MySQL 5.5 上使用此选项将在初始化期间引发适当的错误。 MYSQL_INITDB_SKIP_TZINFO 默认情况下,入口点脚本会自动加载 CONVERT_TZ() 函数所需的时区数据。 如果不需要,任何非空值都会禁用时区加载。 2.4.6. Docker Secrets 作为通过环境变量传递敏感信息的替代方法,_FILE 可以附加到先前列出的环境变量中,从而导致初始化脚本从容器中存在的文件中加载这些变量的值。 特别是,这可用于从存储在 /run/secrets/<secret_name> 文件中的 Docker 机密中加载密码。 例如: $ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql-root -d mysql:tag 目前,这仅支持 MYSQL_ROOT_PASSWORD、MYSQL_ROOT_HOST、MYSQL_DATABASE、MYSQL_USER和 MYSQL_PASSWORD。 2.4.7. 初始化一个新实例 首次启动容器时,将使用提供的配置变量创建并初始化具有指定名称的新数据库。 此外,它将执行 /docker-entrypoint-initdb.d 中的扩展名为 .sh、.sql 和 .sql.gz 的文件。 文件将按字母顺序执行。 您可以通过将 SQL 转储安装到该目录并提供带有贡献数据的自定义镜像来轻松填充您的 mysql 服务。 SQL 文件将默认导入到 MYSQL_DATABASE 变量指定的数据库中。 2.5. 注意事项 2.5.1. 在哪里存储数据 重要提示:有几种方法可以存储在 Docker 容器中运行的应用程序使用的数据。 我们鼓励 mysql 映像的用户熟悉可用的选项,包括: 让 Docker 通过使用自己的内部卷管理将数据库文件写入主机系统上的磁盘来管理数据库数据的存储。 这是默认设置,对用户来说简单且相当透明。 缺点是对于直接在主机系统(即外部容器)上运行的工具和应用程序,可能很难找到这些文件。 在主机系统(容器外部)上创建一个数据目录,并将其挂载到容器内部可见的目录。 这会将数据库文件放置在主机系统上的已知位置,并使主机系统上的工具和应用程序可以轻松访问这些文件。 缺点是用户需要确保目录存在,例如主机系统上的目录权限和其他安全机制设置正确。 Docker 文档是了解不同存储选项和变体的一个很好的起点,并且有多个博客和论坛帖子在该领域讨论和提供建议。 我们将在这里简单地展示上面后一个选项的基本过程: 在主机系统上的合适卷上创建数据目录,例如 /my/own/datadir。 像这样启动你的 mysql 容器: $ docker run --name some-mysql -v /my/own/datadir:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag 命令的 -v /my/own/datadir:/var/lib/mysql 部分将底层主机系统中的 /my/own/datadir 目录挂载为容器内的 /var/lib/mysql ,默认情况下 MySQL 将 写入其数据文件。 2.5.2. 在 MySQL 初始化完成之前没有连接 如果容器启动时没有初始化数据库,则会创建一个默认数据库。 虽然这是预期的行为,但这意味着在初始化完成之前它不会接受传入的连接。 在使用同时启动多个容器的自动化工具(例如 docker-compose)时,这可能会导致问题。 如果您尝试连接到 MySQL 的应用程序没有处理 MySQL 停机时间或等待 MySQL 正常启动,那么在服务启动之前放置一个连接重试循环可能是必要的。 有关官方图像中此类实现的示例,请参阅 WordPress 或 Bonita。 2.5.3. 针对现有数据库的使用 如果您使用已经包含数据库的数据目录(特别是 mysql 子目录)启动 mysql 容器实例,则应该从运行命令行中省略 $MYSQL_ROOT_PASSWORD 变量; 在任何情况下都将被忽略,并且不会以任何方式更改预先存在的数据库。 2.5.4. 以任意用户身份运行 如果你知道你的目录的权限已经被适当地设置了(例如对一个现有的数据库运行,如上所述)或者你需要使用特定的 UID/GID 运行 mysqld,那么可以使用 --user 调用这个镜像设置为任何值(root/0 除外)以实现所需的访问/配置: $ mkdir data$ ls -lnd datadrwxr-xr-x 2 1000 1000 4096 Aug 27 15:54 data$ docker run -v "$PWD/data":/var/lib/mysql --user 1000:1000 --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag 2.5.5. 创建数据库转储 大多数普通工具都可以工作,尽管在某些情况下它们的使用可能有点复杂,以确保它们可以访问 mysqld 服务器。 确保这一点的一种简单方法是使用 docker exec 并从同一容器运行该工具,类似于以下内容: $ docker exec some-mysql sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > /some/path/on/your/host/all-databases.sql 2.5.6. 从转储文件恢复数据 用于恢复数据。 您可以使用带有 -i 标志的 docker exec 命令,类似于以下内容: $ docker exec -i some-mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD"' < /some/path/on/your/host/all-databases.sql 备注 docker安装完MySQL,后面就是MySQL容器在跑,基本上就是当MySQL服务去操作,以前MySQL怎么做现在还是一样怎么做,只是个别操作因为docker包了一层,麻烦一点。 有需要的话,我们也可以基于MySQL官方镜像去定制我们自己的镜像,就比如主从镜像之类的。 本篇文章为转载内容。原文链接:https://blog.csdn.net/muluo7fen/article/details/122731852。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-05-29 17:31:06
101
转载
Docker
Docker , Docker是一款开源的应用容器引擎,它使用容器化技术将应用程序及其依赖项打包在一起,形成一个可移植、自包含的软件单元。在不同的操作系统和环境下,Docker容器可以确保应用的一致性运行,极大地提高了开发、测试和部署的效率与灵活性。 Docker镜像 , Docker镜像是创建Docker容器的基础,是一个只读模板,包含了运行某个软件服务所需的所有文件系统结构、环境变量以及配置信息。在本文中,“liumiaocn/thunder-linux”就是一个迅雷的Docker镜像,通过docker pull命令从Docker Hub仓库下载到本地,然后基于此镜像启动迅雷的Docker容器。 数据卷挂载(-v 参数) , 在Docker中,数据卷是宿主机和容器之间共享数据的一种方式。通过 -v 参数可以在启动容器时指定宿主机目录与容器内部目录的映射关系,使得容器内产生的数据能够持久化存储在宿主机上。在本文的具体场景下,使用 -v $ HOME /Downloads:/root/Downloads 将主机用户的下载目录挂载到容器的根用户下载目录,这样迅雷在容器内下载的文件就可以直接保存在主机的 ~/Downloads 目录下,方便用户在宿主机层面访问和管理这些文件。 X11服务器 (DISPLAY) , X11是一个用于Unix和类Unix系统图形界面显示的网络协议。在Docker容器中运行需要图形界面的应用程序时,通常需要将容器连接到宿主机的X11服务器,以便在宿主机上显示应用程序窗口。在文章中,通过 -e DISPLAY=$DISPLAY 和 -v /tmp/.X11-unix:/tmp/.X11-unix 参数设置,实现了迅雷这个图形界面应用在Docker容器内运行时,其界面能正确显示在宿主机桌面上的功能。
2023-01-28 13:49:08
526
程序媛
转载文章
...略,直接进入第二步会自动下载的) pull 2、启动容器 run 3、进入容器 exec 1、镜像: docker hub官网搜索nginx 下载:docker pull nginx 查看下载情况:docker images 2、容器: 创建容器命令:docker run [-d 后台启动] [–name nginx01 起别名] [-p 3344:80 端口:协议] [镜像(包含版本)] (创建)启动容器实例:docker run -d --name nginx01 -p 3344:80 nginx 查看容器运行状况:docker ps 本机访问测试一下:curl localhost:3344 ■ 端口暴露 -p 宿主机端口:容器内部端口 浏览器输入: http://服务器ip地址:3344/ 3344 是暴露的端口 ----接下来: 进入(正在运行的)容器内部:docker exec -it nginx01 /bin/bash [root@iZwz9535z41cmgcpkm7i81Z /] docker exec -it nginx01 /bin/bashroot@d1a29e4791e3:/ whereis nginxnginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginxroot@d1a29e4791e3:/ cd /etc/nginxroot@d1a29e4791e3:/etc/nginx lsconf.d fastcgi_params mime.types modules nginx.conf scgi_params uwsgi_paramsroot@d1a29e4791e3:/etc/nginx ■ /bin/bash 是Linux的一种常用shell脚本,用于解释执行Linux命令,根据镜像支持的shell的不同,可以使用不同的的shell脚本。 容器,也是和虚拟机一样是虚拟技术呀,通过脚本执行/bin/bash实现,创建并进入容器内部docker ● 思考问题:每次改动nginx配置文件,都需要进入容器内部,十分麻烦: 要是可以在容器外部提供一个映射路径,达到在容器修改文件名,容器内部就可以自动修改?-v 数据卷技术! 二、部署tomcat docker run 可以不用pull,能自动下载 ctrl+c退出 docker pull tomcat:9.0 启动运行,应该加上版本号: docker run -d -p 3355:8080 --name tomcat01 tomcat:9.0 进入容器 docker exec -it tomcat01 /bin/bash ● 部署tomcat,发现问题: 1、linux命令少了 2、没有webapps 这是阿里云镜像的原因:默认使用最小镜像,所有不必要的都剔除了,保证最小可运行环境 可以通过拷贝的方式,解决没有webapps的问题: 在浏览器中输入:http://服务器ip地址:3355/ 进行访问 ● 思考问题:我们以后部署项目,如果每次都要进入容器很麻烦? 要是可以在容器外部提供一个映射路径,webapps,我们在外部放置项目,容器内部就可以自动修改?-v 数据卷技术! 三、部署es+kibana ● Elasticsearch 的问题: es 暴露的端口很多 es 十分耗内存 es 的数据一般需要放置到安全目录!挂载 1、问题1:es 十分耗内存 下载启动运行elastissearch 之后,Linux系统就变得特别卡 # 启动了 linux就卡住了docker stats# 查看 cpu的状态 #es 是十分耗内存的,1.xG# 1核2G(学生机)! # 查看 docker stats 2、问题2:es 需要暴露的端口很多 -p (下载)启动 elasticsearch$ docker run -d --name elasticsearch01 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2 查看内存占用情况docker stats 先感觉stop一下docker stop ba18713ca536 3、es 十分耗内存的解决:增加内存的限制,修改配置文件 -e 环境配置修改 通过 -e 限制内存docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2 [root@iZwz9535z41cmgcpkm7i81Z /] curl localhost:9200/{"name" : "14329968b00f","cluster_name" : "docker-cluster","cluster_uuid" : "0iDu-G_KTo-4X8KORDj1XQ","version" : {"number" : "7.6.2","build_flavor" : "default","build_type" : "docker","build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f","build_date" : "2020-03-26T06:34:37.794943Z","build_snapshot" : false,"lucene_version" : "8.4.0","minimum_wire_compatibility_version" : "6.8.0","minimum_index_compatibility_version" : "6.0.0-beta1"},"tagline" : "You Know, for Search"} 4、思考:用kibana连接elasticsearch? 思考(kibana连接elasticsearch)网络如何连接过去 ☺ 参考来源: 狂神的B站视频《【狂神说Java】Docker最新超详细版教程通俗易懂》 https://www.bilibili.com/video/BV1og4y1q7M4 如果本文对你有帮助的话记得给一乐点个赞哦,感谢! 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_45630258/article/details/124785912。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-12 10:54:44
65
转载
Docker
...管理工具,特别是结合Docker使用后,简直是如虎添翼! 所以今天,咱们就来聊聊这些工具,看看它们能不能成为你心目中的“神器”。 --- 2. Docker 让一切都变得简单 首先,我们得谈谈Docker。Docker是什么?简单来说,它是一种容器化技术,可以让你的应用程序及其依赖项打包成一个独立的“容器”,然后轻松地运行在任何支持Docker的环境中。 举个例子吧,假如你想在一个全新的服务器上安装WordPress,传统方法可能是手动下载PHP、MySQL、Nginx等一堆软件,再逐一配置。而如果你用Docker,只需要一条命令就能搞定: bash docker run --name wordpress -d -p 80:80 \ -v /path/to/wordpress:/var/www/html \ -e WORDPRESS_DB_HOST=db \ -e WORDPRESS_DB_USER=root \ -e WORDPRESS_DB_PASSWORD=yourpassword \ wordpress 这段代码的意思是:启动一个名为wordpress的容器,并将本地目录/path/to/wordpress挂载到容器内的/var/www/html路径下,同时设置数据库连接信息。是不是比传统的安装方式简洁多了? 不过,单独使用Docker虽然强大,但对于不熟悉命令行的人来说还是有点门槛。这时候就需要一些辅助工具来帮助我们更好地管理和调度容器了。 --- 3. Portainer 可视化管理Docker的好帮手 Portainer绝对是我最近发现的一颗“宝藏”。它的界面非常直观,几乎不需要学习成本。不管是想看看现有的容器啥情况,还是想启动新的容器,甚至连网络和卷的管理,都只需要动动鼠标拖一拖、点一点就行啦! 比如,如果你想快速创建一个新的MySQL容器,只需要打开Portainer的Web界面,点击“Add Container”,然后填写几个基本信息即可: yaml image: mysql:5.7 name: my-mysql ports: - "3306:3306" volumes: - /data/mysql:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: rootpassword 这段YAML配置文件描述了一个MySQL容器的基本参数。Portainer会自动帮你解析并生成对应的Docker命令。是不是超方便? 另外,Portainer还有一个特别棒的功能——实时监控。你打开页面就能看到每个“小房子”(就是容器)里用掉的CPU和内存情况,而且还能像穿越空间一样,去访问别的机器上跑着的那些“小房子”(Docker实例)。这种功能对于运维人员来说简直是福音! --- 4. Rancher 企业级的容器编排利器 如果你是一个团队协作的开发者,或者正在运营一个大规模的服务集群,那么Rancher可能是你的最佳选择。它不仅仅是一个Docker管理工具,更是一个完整的容器编排平台。 Rancher的核心优势在于它的“多集群管理”能力。想象一下,你的公司有好几台服务器,分别放在地球上的不同角落,有的在美国,有的在欧洲,还有的在中国。每台服务器上都跑着各种各样的服务,比如网站、数据库啥的。这时候,Rancher就派上用场了!它就像一个超级贴心的小管家,让你不用到处切换界面,在一个地方就能轻松搞定所有服务器和服务的管理工作,省时又省力! 举个例子,如果你想在Rancher中添加一个新的节点,只需要几步操作即可完成: 1. 登录Rancher控制台。 2. 点击“Add Cluster”按钮。 3. 输入目标节点的信息(IP地址、SSH密钥等)。 4. 等待几分钟,Rancher会自动为你安装必要的组件。 一旦节点加入成功,你就可以直接在这个界面上部署应用了。比如,用Kubernetes部署一个Redis集群: bash kubectl create deployment redis --image=redis:alpine kubectl expose deployment redis --type=LoadBalancer --port=6379 虽然这条命令看起来很简单,但它背后实际上涉及到了复杂的调度逻辑和网络配置。而Rancher把这些复杂的事情封装得很好,让我们可以专注于业务本身。 --- 5. Traefik 反向代理与负载均衡的最佳拍档 最后要介绍的是Traefik,这是一个轻量级的反向代理工具,专门用来处理HTTP请求的转发和负载均衡。它最厉害的地方啊,就是能跟Docker完美地融为一体,还能根据容器上的标签,自动调整路由规则呢! 比如说,你有两个服务分别监听在8080和8081端口,现在想通过一个域名访问它们。只需要给这两个容器加上相应的标签: yaml labels: - "traefik.enable=true" - "traefik.http.routers.service1.rule=Host(service1.example.com)" - "traefik.http.services.service1.loadbalancer.server.port=8080" - "traefik.http.routers.service2.rule=Host(service2.example.com)" - "traefik.http.services.service2.loadbalancer.server.port=8081" 这样一来,当用户访问service1.example.com时,Traefik会自动将请求转发到监听8080端口的容器;而访问service2.example.com则会指向8081端口。这种方式不仅高效,还极大地减少了配置的工作量。 --- 6. 总结 找到最适合自己的工具 好了,到这里咱们已经聊了不少关于服务器管理工具的话题。从Docker到Portainer,再到Rancher和Traefik,每一种工具都有其独特的优势和适用场景。 我的建议是,先根据自己的需求确定重点。要是你只想弄个小玩意儿,图个省事儿快点搞起来,那用Docker配个Portainer就完全够用了。但要是你们团队一起干活儿,或者要做大范围的部署,那Rancher这种专业的“老司机工具”就得安排上啦! 当然啦,技术的世界永远没有绝对的答案。其实啊,很多时候你会发现,最适合你的工具不一定是最火的那个,而是那个最合你心意、用起来最顺手的。就像穿鞋一样,别人觉得好看的根本不合脚,而那双不起眼的小众款却让你走得又稳又舒服!所以啊,在用这些工具的时候,别光顾着看,得多动手试试,边用边记下自己的感受和想法,这样你才能真的搞懂它们到底有啥门道! 好了,今天的分享就到这里啦!如果你还有什么问题或者想法,欢迎随时留言交流哦~咱们下次再见啦!
2025-04-16 16:05:13
97
月影清风_
Docker
Docker , Docker是一种开源的应用容器引擎,通过将应用程序及其依赖项打包到一个可移植的容器中,实现了一种轻量级、隔离且可复制的软件部署方式。在本文中,Docker被用于简化数据库(如MySQL)的部署、测试和管理流程,通过创建和运行包含数据库服务的容器,使得开发者能够轻松地在不同环境中保持一致的服务配置,并能方便地进行数据持久化存储。 数据持久化 , 在计算机科学领域,特别是在容器技术中,数据持久化是指将数据保存在容器生命周期之外,即使容器停止或重启后仍然可以访问这些数据。在使用Docker部署数据库时,为了确保重要的数据库信息不会因为容器的启动、关闭或迁移而丢失,需要采取措施如挂载宿主机目录或使用特定的数据卷来实现数据持久化。 MySQL容器 , 在Docker环境下,MySQL容器指的是基于官方或自定义MySQL镜像运行的一个独立的、具有完整MySQL数据库服务功能的Docker容器实例。通过在容器内部安装并运行MySQL服务器,用户可以在不依赖于宿主机具体环境的情况下,快速搭建和管理MySQL数据库,同时借助Docker提供的资源隔离和灵活管理特性,实现对数据库服务的高效运维和扩展。 Docker Hub , Docker Hub是一个集中式仓库,提供Docker镜像的托管与分发服务。在文中,用户需要从Docker Hub上下载MySQL镜像以创建数据库容器。它不仅是全球最大的Docker镜像库,还支持用户上传自己的私有镜像,并通过版本管理和自动化构建等功能,极大地促进了容器化应用的开发和交付过程。
2024-01-12 17:40:23
536
代码侠
Docker
序号: 一、什么是Docker Docker 是一种轻量级的容器化平台,它可以帮助开发者更方便地构建、部署和运行应用。 Docker 之所以被称为容器化平台,是因为它可以将应用及其相关依赖项打包成一个容器,这个容器可以在不同的环境中运行,而无需担心底层操作系统的差异。 例如,在本地开发时,我们通常会安装所有必要的依赖项,并且配置环境变量,以便应用能够正确运行。然而,当你准备把应用推到生产环境这个“战场”时,可得琢磨琢磨许多其他的要素,比如说安全性、性能表现、还有能不能随需求灵活扩展这些个问题。这时,Docker就可以派上用场了。 Docker 可以将应用及其依赖项打包成一个容器,这个容器包含了应用所需的所有内容,包括操作系统、环境变量、配置文件等。这样一来,甭管你在哪个环境下运行,只要手头有个 Docker 容器,就能稳稳当当地保证应用的稳定性和一致性,就像你走到哪都能带着自己的小宇宙一样,随时随地给你提供稳定可靠的表现。 二、Docker的工作原理 Docker 的工作原理主要有两个方面: 1.镜像 Docker 使用镜像作为基础环境,镜像是一个只读的数据层,其中包含了一切构建应用所需的文件和设置。我们可以从官方仓库下载已有的镜像,也可以自己创建自己的镜像。 例如,我们可以从官方仓库下载一个基于 Ubuntu 的镜像,然后在这个基础上安装 Node.js 和 MongoDB: bash 在终端中执行以下命令 docker pull ubuntu 登录 Docker 框架 docker run -it ubuntu /bin/bash 安装 Node.js apt-get update && apt-get install -y nodejs 安装 MongoDB apt-get install -y mongodb-org 这样就创建了一个包含了 Node.js 和 MongoDB 的 Docker 镜像。 2.容器 当我们有了一个镜像后,就可以创建一个容器了。容器就像是Docker里实实在在跑应用的小天地,它就像乐高积木一样,可以从一个镜像构建出来。你随时可以对这个小天地进行启动、暂停、重启等各种操作,就像你在现实生活中管理你的小天地一样灵活自如。 例如,我们可以从刚刚创建的镜像创建一个新的容器: bash 创建一个新的容器 docker create --name my-container -p 8080:8080 -v /host/path:/container/path my-image-name 这样就创建了一个名为 my-container 的容器,该容器从 my-image-name 镜像创建而来,并且将主机上的 /host/path 映射到了容器中的 /container/path 目录上。 三、Docker的优势 使用 Docker 可以带来许多优势: 1.快速开发和部署 使用 Docker 可以快速地构建、测试和部署应用,因为它提供了一个一致性的环境,避免了在不同环境中可能出现的问题。 2.节省资源 使用 Docker 可以节省大量的资源,因为每个容器都是独立的,它们不会共享宿主机的资源。 3.提高可靠性 使用 Docker 可以提高应用的可靠性,因为每个容器都是独立的,即使某个容器崩溃,也不会影响其他容器。 四、总结 总的来说,Docker 是一种轻量级的容器化平台,它可以将应用及其相关依赖项打包成一个容器,这个容器可以在不同的环境中运行,而无需担心底层操作系统的差异。使用 Docker 可以带来许多优势,包括快速开发和部署、节省资源、提高可靠性等。 我是一个 AI,但我希望能为你提供有用的文章。嘿,我真心希望通过这篇文章,你能对Docker有个更接地气、更透彻的理解。要是你脑袋里蹦出了任何疑问或者困惑,别犹豫,就像和朋友聊天那样,随时向我抛过来吧!
2023-08-13 11:28:22
537
落叶归根_t
Docker
...lumes) , 在Docker容器技术中,数据卷是一种独立于容器生命周期的持久化存储机制。它是一个存在于宿主机上的目录或文件,可以被挂载到容器内部的特定路径,使得容器内外的数据能够实现共享和持久存储。即使创建数据卷的容器被删除,该数据卷中的数据仍然会被保留,确保了数据的安全性和持久性。 Docker守护进程(Docker Daemon) , Docker守护进程是运行在宿主机上负责管理和控制Docker容器的核心服务程序。它可以接收并处理来自客户端的各种命令,如创建、启动、停止容器,管理网络、存储等资源。通过配置Docker守护进程的启动参数(例如在/etc/docker/daemon.json文件中设置data-root),用户可以自定义Docker的相关行为和配置,包括修改默认的Docker存储路径。 PersistentVolumes(PV)和PersistentVolumeClaims(PVC) , 这两个名词来源于Kubernetes编排系统,用于解决集群环境中数据持久化的高级需求。PersistentVolumes是集群管理员提供的预配置存储资源,而PersistentVolumeClaims则是由应用开发者声明的对存储资源的需求。当一个PVC请求与一个PV匹配成功后,Kubernetes会将这个持久化存储资源动态绑定给应用使用,从而实现了存储资源的跨节点共享和自动分配,在多容器、多节点场景下保证了数据的持久性和可移植性。尽管PV和PVC的概念在这篇文章的主体部分未直接提及,但它们作为容器编排领域内对于存储管理的重要概念,有助于读者理解在更复杂的容器环境下的存储解决方案。
2023-09-10 14:02:30
541
繁华落尽_
Etcd
...ubernetes、Docker Swarm等众多容器编排平台中以实现集群的配置共享和协调服务。不过,在我们日常运维的时候,难免会遇到一些突发状况。比如硬件突然闹脾气出故障啦、网络波动捣乱不稳定啦,甚至有时候人为操作的小失误也可能让Etcd这位小伙伴意外地挂掉,没法正常工作。那么,实际情况中,当Etcd遇到重启后需要恢复数据的状况时,它是怎么巧妙应对的呢?接下来,咱们就通过一些实实在在的代码实例,来一起把这个话题掰开了、揉碎了,好好地研究探讨一番。 1. Etcd的数据持久化机制 首先,我们需要了解Etcd的数据持久化方式。Etcd采用Raft一致性算法保证数据的一致性和高可用性,其数据默认保存在本地磁盘上(可通过--data-dir配置项指定目录),并定期进行快照(snapshot)和日志记录,确保即使在异常情况下也能尽可能减少数据丢失的风险。 bash 启动etcd时设置数据存储目录 etcd --data-dir=/var/lib/etcd 2. 非正常关闭与重启恢复流程 当Etcd非正常关闭后,重启时会自动执行以下恢复流程: (1)检测数据完整性:Etcd启动时,首先会检查data-dir下的快照文件和日志文件是否完整。要是发现文件受损或者不齐全,它会像个贴心的小助手那样,主动去其它Raft节点那里借个肩膀,复制丢失的日志条目,以便把状态恢复重建起来。 (2)恢复Raft状态:基于Raft协议,Etcd通过读取并应用已有的日志和快照文件来恢复集群的最新状态。这一过程包括回放所有未提交的日志,直至达到最新的已提交状态。 (3)恢复成员关系与领导选举:Etcd根据持久化的成员信息重新建立集群成员间的联系,并参与领导选举,以恢复集群的服务能力。 go // 这是一个简化的示例,实际逻辑远比这复杂 func (s EtcdServer) start() error { // 恢复raft状态 err := s raft.Restore() if err != nil { return err } // 恢复成员关系 s.restoreCluster() // 开始参与领导选举 s.startElection() // ... } 3. 数据安全与备份策略 尽管Etcd具备一定的自我恢复能力,但为了应对极端情况下的数据丢失,我们仍需要制定合理的备份策略。例如,可以使用Etcd自带的etcdctl snapshot save命令定期创建数据快照,并将其存储到远程位置。 bash 创建Etcd快照并保存到指定路径 etcdctl snapshot save /path/to/snapshot.db \ --endpoint=https://etcd-cluster-0:2379,https://etcd-cluster-1:2379 如遇数据丢失,可使用etcdctl snapshot restore命令从快照恢复数据,并重新加入至集群。 bash 从快照恢复数据并启动一个新的etcd节点 etcdctl snapshot restore /path/to/snapshot.db \ --data-dir=/var/lib/etcd-restore \ --initial-cluster-token=etcd-cluster-unique-token 4. 结语与思考 面对Etcd非正常关闭后的重启数据恢复问题,我们可以看到Etcd本身已经做了很多工作来保障数据的安全性和系统的稳定性。但这可不代表咱们能对此放松警惕,摸透并熟练掌握Etcd的运行原理,再适时采取一些实打实的备份策略,对提高咱整个系统的稳定性、坚韧性可是至关重要滴!就像人的心跳一旦不给力,虽然身体自带修复技能,但还是得靠医生及时出手治疗,才能最大程度地把生命危险降到最低。同样,我们在运维Etcd集群时,也应该做好“医生”的角色,确保数据的“心跳”永不停息。
2023-06-17 09:26:09
712
落叶归根
MySQL
.... 引言 当我们使用Docker来部署MySQL数据库时,一个常常引起开发者好奇心的现象是:即使我们没有明确指定MySQL数据存储的宿主机目录进行挂载,Docker仍然会为我们自动配置一个数据卷。这究竟是怎么一回事儿,为啥Docker会做出这样的选择呢?别急,本文就要带你一起揭开这个谜底,就像探险家挖掘宝藏那样,我们会通过实实在在的代码实例,一步步揭示这背后的神秘机制和它所带来的实际价值,让你恍然大悟,拍案叫绝! 1. Docker数据卷的概念与作用 首先,让我们回顾一下Docker数据卷(Data Volume)的基本概念。在Docker的天地里,数据卷可是个了不起的角色。它就像一个超长待机的移动硬盘,不随容器的生死存亡而消失,始终保持独立。也就是说,甭管你的容器是歇菜重启了,还是彻底被删掉了,这个数据卷都能稳稳地保存住里面的数据,让重要信息时刻都在,安全无忧。对于像MySQL这样的数据库服务而言,数据的持久性尤为重要,因此默认配置下,Docker会在启动MySQL容器时不经意间创建一个匿名数据卷以保证数据安全。 2. MySQL容器未显式挂载data目录时的行为 当我们在不设置任何数据卷挂载的情况下运行MySQL Docker镜像,Docker实际上会自动生成一个匿名数据卷用于存放MySQL的数据文件。这是因为Docker官方提供的MySQL镜像已经预设了数据目录(如/var/lib/mysql)为一个数据卷。例如,如果我们执行如下命令: bash docker run -d --name mysql8 -e MYSQL_ROOT_PASSWORD=your_password mysql:8.0 虽然这里没有手动指定-v或--mount选项来挂载宿主机目录,但MySQL容器内部的数据变化依旧会被持久化存储到Docker管理的一个隐藏数据卷中。 3. 查看自动创建的数据卷 若想验证这个自动创建的数据卷,可以通过以下命令查看: bash docker volume ls 运行此命令后,你会看到一个无名(匿名)卷,它就是Docker为MySQL容器创建的用来持久化存储数据的卷。 4. 明确指定数据卷挂载的优势 尽管Docker提供了这种自动创建数据卷的功能,但在实际生产环境中,我们通常更倾向于明确地将MySQL的数据目录挂载至宿主机上的特定路径,以便更好地管理和备份数据。比如: bash docker run -d \ --name mysql8 \ -v /path/to/host/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=your_password \ mysql:8.0 在此示例中,我们指定了MySQL容器内的 /var/lib/mysql 目录映射到宿主机上的 /path/to/host/data。这么做的妙处在于,我们能够直接在主机上对数据库文件“动手”,不论是备份还是迁移,都不用费劲巴拉地钻进容器里面去操作了。 5. 结论与思考 Docker之所以在启动MySQL容器时不显式配置也自动创建数据卷,是为了保障数据库服务的默认数据持久化需求。不过,对于我们这些老练的开发者来说,一边摸透和掌握这个机制,一边也得明白一个道理:为了追求更高的灵活性和可控性,咱应该积极主动地去声明并管理数据卷的挂载点,就像是在自己的地盘上亲手搭建一个个储物柜一样。这样一来,我们不仅能确保数据安全稳妥地存起来,还能在各种复杂的运维环境下游刃有余,让咱们的数据库服务变得更加结实耐用、值得信赖。 总的来说,Docker在简化部署流程的同时,也在幕后默默地为我们的应用提供了一层贴心保护。每一次看似“自动”的背后,都蕴含着设计者对用户需求的深刻理解和精心考量。在我们每天的工作里,咱们得瞅准自己项目的实际需求,把这些特性玩转起来,让Docker彻底变成咱们打造微服务架构时的得力小助手,真正给力到家。
2023-10-16 18:07:55
127
烟雨江南_
Maven
...rchetype插件创建项目模板后,我们还可以进一步探索Maven生态系统的更多创新实践和前沿应用。近期,Apache Maven 4.0版本已在开发进程中,预计将进一步优化依赖管理和构建速度,同时可能引入对新Java特性更全面的支持,这将直接影响到archetype插件的性能与功能。 实际上,许多大型企业及开源社区都在积极探索利用Maven archetype实现工程化、自动化项目初始化的最佳方案。例如,Spring Boot团队就提供了丰富的官方archetype集合,开发者可以直接基于这些模板快速启动新的Spring Boot应用,大大简化了初始配置流程。 此外,随着云原生时代的到来,Kubernetes和Docker等容器技术的广泛应用,一些集成Maven archetype的工具如Jenkins X开始崭露头角,它们能够结合云环境特点,通过自定义archetype自动化生成符合云原生规范的项目结构,实现持续交付和部署流水线的一体化构建。 对于希望深入研究Maven archetype并将其应用于实际工作中的开发者来说,可以关注以下资源: 1. Apache Maven官方文档,获取最新版本更新内容及最佳实践指南; 2. Spring Boot官方Archetype列表,学习如何创建并扩展自定义模板; 3. 关注DevOps领域中关于Maven archetype与云原生、持续集成/持续部署(CI/CD)实践的案例分享和技术文章; 4. 参与相关论坛和社区讨论,了解业界如何解决利用Maven archetype面临的复杂场景问题,不断提升自身技术水平和工作效率。
2024-03-20 10:55:20
109
断桥残雪
转载文章
...ls -a:显示所有目录,文件夹,隐藏文件/目录 ls -l:显示文件的权限、修改时间等 ls -al:上面两个结合 ls 目录:显示该目录下的文件 – cd /:进入linux根目录 cd ~:/home/jl – uname :查看系统信息 uname -a :查看全部系统信息 – cat 文件名:显示某文件内容 – sudo :临时切换root用户 sudo apt-get install 软件名 :装某软件 sudo su:直接切换root用户(少用) sudo su jl:切换回普通用户 – touch 文件名:创建文件 rm -r 目录/文件:删除文件/目录及它包含的所有内容 rm -f 文件:直接删除,无需确认 rm -i 文件:删除文件,会逐一询问是否删除 rmdir 目录:专门删除目录 mv :可以用来移动文件/目录,也可以用来重命名 – ifconfig:显示网络配置信息(lo:本地回环测试) ifconfig -a:显示所有网卡(上面只显示工作的,本条显示所有工作和未工作的) ifconfig eth0 up:打开eth0这个网卡 ifconfig eth0 down:关闭eth0这个网卡(0一般要sudo来执行) ifconfig eth0 你想设置的地址:重设eth0的ip地址 – 命令 --help:看看这个命令的帮助信息 reboot:重启 – sync:数据同步写入磁盘命令(一般来说,用户写的内容先保存在一个缓冲区,系统是隔一定时间像磁盘写入缓冲区内写入磁盘),用sync立刻写入 grep ”“ -i :搜索时忽略大小写 grep 默认是匹配字符, -w 选项默认匹配一个单词 例如我想匹配 “like”, 不加 -w 就会匹配到 “liker”, 加 -w 就不会匹配到 du 目录/文件 -sh : 查看某一文件/目录的大小,也可以到一个目录下du -sh,查看这个目录的大小 目录下使用du -sh 查看目录总的大小 du 文件名 -sh 查看指定文件的大小 df:检查linux服务器的文件系统磁盘空间占用情况,默认以kb为单位 gedit 文件:使用gedit软件打开一个文件(类似于windows下面的记事本) ps:查看您当前系统有哪些进程,ubuntu(多用户)下是ps -aux,嵌入式linux(单用户)下面是ps top:进程实时运行状态查询 file 文件名:查看文件类型 ubuntu的fs cd / :根目录,一切都是从根目录发散开来的 /bin:存放二进制可执行文件,比如一些命令 /boot:ubuntu的内核与启动文件 /cdrom:有光盘是存放光盘文件 /dev:存放设备驱动文件 /etc:存放配置文件,如账号和密码文件(加密后的) /home:系统默认的用户主文件夹 /lib:存放库文件 /lib64:存放库文件,. so时linux下面的动态库文件 /media:存放可插拔设备,如sd,u盘就是挂载到这个文件下面 /mnt:用户可使用的挂载点,和media类似,可以手动让可插拔设备挂载到/mnt /opt:可选的文件和程序存放目录,给第三方软件放置的目录 /proc:存放系统的运行信息,实在内存上的不是在flash上,如cat /proc/cpuinfo /root:系统管理员目录,root用户才能访问的文件 /sbin:和bin类似,存放一些二进制可执行文件,sbin下面一般是系统开机过程中所需要的命令 /srv:服务相关的目录,如网络服务 /sys:记录内核信息,是虚拟文件系统 /tmp:临时目录 /usr:不是user的缩写,而是UNIX Software Resource的缩写,存放系统用户有关的文件,占很大空间 /var:存放变化的文件,如日志文件 – 移植就是移植上面这些文件 磁盘管理 linux开发一定要选用FAT32格式的U盘或者SD卡 u盘在/dev中的名字是sd,要确定是哪个,拔了看少了哪个。就是哪个 /dev/sdb表示U盘,/dev/sdb1表示U盘的第一个分区,一般U盘 sd卡只有一个分区 df:显示linux系统的磁盘占用情况 在一个目录里使用du -sh:查看这个目录里面所有内容所占用的资源 du 文件名 -sh:一般用来看单个文件/目录的大小 du -h --max-depth=n:显示n级目录的大小 – 磁盘的挂载与取消挂载: mount 和 umount sudo mount /dev/sdb1 /media/jl/udisk sudo umount /media/jl/u盘名 (-f 强制取消挂载),如果u盘正在使用,如被另一个终端打开,那么该指令无效 mount挂载后中文显示乱码的解决方法 sudo mount -o iocharset=utf8 /dev/sdb1 udisk – 磁盘的分区和格式化 sudo fdisk -l /dev/sdb 查看所有分区信息(–help查看别的用法) sudo fdisk /dev/sdb1 ----> m ( 进入帮助 ) ----> d 删除该分区 ----> wq 保存并退出 mkfs -t vfat /dev/sdb1 mkfs -t vfat /dev/sdb2 mkfs -t vfat /dev/sdb3 给分区1,2,3分别格式化,完成后能在图形界面看见三个u盘图标 格式化u盘之前一定要先卸载u盘已经挂载的系统。 – 压缩和解压缩 linux下常用的压缩扩展名: .tar .tar.bz2 .tar.gz 后两个linux常用 windows下面用7zip软件 右键选中文件,选择7zip,添加到压缩包,压缩格式选择tar,仅存储 生成tar文件,这里只是打包,没有压缩 右键上面的tar文件,选择7zip,添加到压缩包,压缩格式选择bzip2,确定 生成.tar.bz2文件,把它放到ubuntu解压 ubuntu也支持解压.tar和.zip,但后面两个常用 – ubuntu下面的压缩工具时gzip 压缩文件 gzip 文件名:压缩文件,变成 原文件名.gz,原来的文件就不见了 解压缩文件 gzip -d .gz:还原 文件 gzip -r 目录:递归,将该目录里的各个文件压缩,不提供打包服务 – bzip2工具负责压缩和解压缩.bz2格式的压缩包 bzip2 -z 文件名,压缩成 文件名.bz2 bzip2 -d 文件名.bz2,解压缩成 文件名 bzip2不能压缩/解压缩 目录 – 打包工具 tar 常用参数 -f:使用归档文件(必须要在所有选项后面) -c:创建一个新归档 -x:从归档中解出文件 -j:使用bzip2压缩格式 -z:使用gzip压缩格式 -v:打印出命令执行过程 如以bzip2格式压缩,打包 tar -vcjf 目录名.tar.bz2 目录名 如将上面的压缩包解包 tar -vxjf 目录名.tar.bz2 – 其他压缩工具 rar工具 sudo apt-get install rar(用dhcp连不上阿里云的镜像) rar a test.rar test 把test压缩成test.rar rar x test.rar 把test.rar解压缩成test – zip工具 压缩 zip -rv test.zip test 解压缩 unzip test.zip – ubuntu的用户和用户组 linux是多用户的os,不同的用户有不同的权限,可以查看和操作不同的文件 有三种用户 1、初次用户 2、root用户 3、普通用户 root用户可以创建普通用户 linux用户记录在/etc/passwd这个文件内 linux用户密码记录在/etc/shadow这个文件内,不是以明文记录的 每个用户都有一个id,叫做UID – linux用户组 为了方便管理,将用户进行分组,每个用户可以属于多个组 可以设置非本组人员不能访问一些文件 用户和用户组的存在就是为了控制文件的访问权限的 每个用户组都有一个ID,叫做GID 用户组信息存储在/etc/group中 passwd 用户名:修改该用户的密码 – ubuntu文件权限 ls -al 文件名 如以b开头: -brwx - rwx - rwx -:b表示 块文件,设备文件里面可供存储的周边设备 以d开头是目录 以b是块设备文件 以-开头是普通文件 以 l 开头表示软连接文件 以c开头是设备文件里的串行端口设备 -rwx - rwx - rwx -:用户权限,用户组内其他成员,其它组用户 数字 1 表示链接数,包括软链接和硬链接 第三列 jl 表示文件的拥有者 第四列 jl 表示文件的用户组 第五列 3517 表示这个文件的大小,单位是字节 ls -l 显示的文件大小单位是字节 ls -lh 现实的文件大小单位是 M / G 第六七八列是最近修改时间 最后一列是文件名 – 修改文件权限命令 chmod 777 文件名 修改文件所属用户 sudo chown root 文件 修改文件用户组 sudo chown .root 文件 同时修改文件用户和用户组 sudo chown jl.jl 文件 修改目录的用户/用户组 sudo chown -r jl.jl 目录( root.root ) – linux连接文件 1、硬连接 2、符号连接(软连接) linux有两种连接文件,软连接/符号连接,硬连接 符号连接类似于windows下面的快捷方式 硬连接通过文件系统的inode连接来产生新文件名,而不是产生新文件 inode:记录文件属性,一个文件对应一个inode, inode相当于文件ID 查找文件要先找到inode,然后才能读到文件内容 – ln 命令用于创建连接文件 ln 【选项】源文件 目标文件 不加选项就是默认创建硬连接 -s 创建软连接 -f 强制创建连接文件,如果目标存在,就先删掉目标文件,再创建连接文件 – 硬连接:多个文件都指向同一个inode 具有向inode的多个文件互为硬连接文件,创建硬连接相当于文件实体多了入口 只有删除了源文件、和它所有的硬连接文件,晚间实体才会被删除 可以给文件创建硬连接来防止文件误删除 改了源文件还是硬连接文件,另一个文件的数据都会被改变 硬连接不能跨文件系统(另一个格式的u盘中的文件) 硬连接不能连接到目录 出于以上原因,硬连接不常用 ls -li:此时第一列显示的就是每个文件的inode – 软连接/符号连接 类似windows下面的快捷方式 使用较多 软连接相当于串联里一个独立的文件,该文件会让数据读取指向它连接的文件 ln -s 源文件 目标文件 特点: 可以连接到目录 可以跨文件系统 删除源文件,软连接文件也打不开了 软连接文件通过 “ -> ” 来指示具体的连接文件(ls -l) 创建软连接的时候,源文件一定要使用绝对路径给出,(硬连接无此要求) 软连接文件直接用cp复制到别的目录下,软连接文件就会变成实体文件,就算你把源文件删掉,该文件还是有效 正确的复制、移动软连接的用法是:cp -d 如果不用绝对路径,cp -d 软连接文件到别的目录,该软连接文件就会变红,失效 如果用了绝对路径,cp -d 软连接文件到别的目录,该软连接文件还是有效的,还是软连接文件 不用绝对路径,一拷贝就会出问题 – 软连接一个目录,也是可以用cp -d复制到其他位置的 – gedit 是基于图形界面的 vim有三种模式: 1、一般模式:默认模式,用vim打开一个文件就自动进入这个模式 2、编辑模式:按 i,a等进入,按esc回到一般模式 3、命令行/底行模式:在一般模式下输入:/ ?可进入命令行模式 ,按esc回到一般模式 一般模式下,dd删除光标所在的一整行; ndd,删除掉光标所在行和下面的一共n行 点 . 重复上一个操作 yy复制光标所在行 小p复制到光标下一行 大p复制到光标上一行n nyy复制光标所在往下n行 设置vim里的tab是四个空格:在/etc/vim/vimrc里面添加:set ts=4 设置vim中显示行号:在上面那个文件里添加:set nu – vscode是编辑器 gcc能编译汇编,c,cpp 电脑上的ubuntu自带的gcc用来编译x86架构的程序,而嵌入式设备的code要用针对于该芯片架构如arm的gcc编译器,又叫做交叉编译器(在一种架构的电脑上编译成另一种架构的代码) gcc -c 源文件:只编译不链接,编译成.o文件 -o 输出文件名( 默认名是 .out ) -O 对程序进行优化编译,这样产生的可执行文件执行效率更高 -O2:比-O幅度更大的优化,但编译速度会很慢 -v:显示编译的过程 gcc main.c 输出main.out的可执行文件 预处理 --> 编译 --> 汇编 --> 链接 – makefile里第一个目标默认是终极目标 其他目标的顺序可以变 makefile中的变量都是字符串 变量的引用方法 : $ ( 变量名 ) – Makefile中执行shell命令默认会把命令本身打印出来 如果在shell命令前加 @ ,那么shell’命令本身就不会被打印 – 赋值符:= 变量的有效值取决于他最后一次被赋值的值 : = 赋值时右边的值只是用前面已经定义好的,不会使用后面的 ?= 如果左边的前面没有被赋值,那么在这里赋值,佛则就用前面的赋值 + = 左边前面已经复制了一些字串,在这里添加右边的内容,用空格隔开 – 模式规则 % . o : % . c %在这里意思是通配符,只能用于模式规则 依赖中 % 的内容取决于目标 % 的内容 – CFLAGS:指定头文件的位置 LDFLAGS:用于优化参数,指定库文件的位置 LIBS:告诉链接器要链接哪些库文件 VPATH:特殊变量,指定源文件的位置,冒号隔开,按序查找源文件 vpath:关键字,三种模式,指定、清除 – 自动化变量 $ @ 规则中的目标集合 $ % 当目标是函数库的时候,表示规则中的目标成员名 $ < 依赖文件集合中的第一个文件,如果依赖文件是以 % 定义的,那么 $ < 就是符合模式的一系列文件的集合 $ ? 所有比目标新的依赖文件的集合,以空格分开 $ ^ 所有依赖文件的集合,用空格分开,如果有重复的依赖文件,只保留一次 $ + 和 $ ^ 类似,但有多少重复文件都会保留 $ 表明目标模式中 % 及其以前的部分 如果目标是 test/a.test.c,目标模式是 a.%.c,那么 $ 就表示 test/a.test – 常用的是 $@ , $< , $^ – Makefile的伪目标 不生成目标文件,只是执行它下面的命令 如果被错认为是文件,由于伪目标一般没有依赖,那么目标就被认为是最新的,那么它下面的命令就不会执行 。 如果目录下有同名文件,伪目标错认为是该文件,由于没有依赖,伪目标下面的指令不会被执行 伪目标声明方法 .PHONY : clean 那么就算目录下有伪目标同名文件,伪目标也同样会执行 – 条件判断 ifeq ifneq ifdef ifndef – makefile函数使用 shell脚本 类似于windoes的批处理文件 将连续执行的命令写成一个文件 shell脚本可以提供数组,循环,条件判断等功能 开头必须是:!/bin/bash 表示使用bash 脚本的扩展名:.sh – 交互式shell 有输入有输出 输入:read 第三行 name在这里作为变量,read输入这个变量 下一行使用这个变量直接是 $name,不用像 Makefile 里面那样子加括号 read -p “读取前你想打印的内容” 变量1 变量2 变量3… – 数值计算 第五行等于号两边不能有空格 右边计算的时候是 $( ( ) ),注意要两个括号 – test 测试命令 文件状态查询,字符、数字比较 && cmd1 && cmd2 当cmd1执行完并且正确,那么cmd2也执行 当cmd2执行完并且错误,那么cmd2不执行 || cmd1 || cmd2 当cmd1执行完并且正确,那么cmd2不执行 当cmd2执行完并且错误,那么cmd2也执行 查看一个文件是否存在 – 测试两个字符串是否相等 ==两边必须要有空格,如果不加空格,test这句就一直是对的。 – 中括号判断符 [ ] 作用和test类似 里面只能输入 == 或者 != 四个箭头所指必须用空格隔开 而且如果变量是字符串的话,一定要加双引号 – 默认变量 $0——shell脚本本身的命令 $——最后一个参数的标号(1,2,3,4…) $@——表示 $1 , $2 , $3 … $1 $2 $3 – shell 脚本的条件判断 if [ 条件判断 ];then //do something fi 红点处都要加空格 exit 0——表示退出 – if 条件判断;then //do something elif 条件判断;them //do something else //do something fi 红线处要加空格 – case 语句 case $var in “第一个变量的内容”) //do something ;; “第二个变量的内容”) // do something ;; . . . “第n个变量的内容”) //do something ;; esac 不能用 “”,否则就不是通配符的意思,而是表示字符 – shell 脚本函数 function fname(){ //函数代码段 } 其中function可以写也可以不写 调用函数的时候不要加括号 shell 脚本函数传参方式 – shell 循环 while[条件] //括号内的状态是判断式 do //循环代码段 done – until [条件] do //循环代码段 done – for循环,使用该循环可以知道有循环次数 for var con1 con2 con3 … … do //循环代码段 done – for 循环数值处理 for((初始值;限制值;执行步长)) do //循环代码段 done – 红点处必须要加空格!! loop 环 – – 注意变量有的地方用了 $ ,有的地方不需要 $ 这里的赋值号两边都不用加 空格 $(())数值运算 本篇文章为转载内容。原文链接:https://blog.csdn.net/engineer0/article/details/107965908。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-11-23 17:18:30
79
转载
转载文章
...线学习的播放视频。 目录 内容会比较多,小伙伴门可以根据目录进行按需查阅。 文章目录 😎 知识点概览 目录 一、学习页面:查询课程计划 0x01 需求分析 0x02 Api接口 0x03 服务端开发 Controller Service 测试 0x04 前端开发 配置NGINX虚拟主机 前端 API 方法 前端 API 方法调用 测试 二、学习页面:获取视频播放地址 0x01 需求分析 0x02 课程发布:储存媒资信息 需求分析 数据模型 Dao Service 测试 0x03 Logstash:扫描课程计划媒资 创建索引 创建模板文件 配置 mysql.conf 启动 logstash.bat Logstash多实例运行 0x04 搜素服务:查询课程媒资接口 需求分析 Api接口定义 Service Controller 测试 三、在线学习:接口开发 0x01 需求分析 0x02 搭建开发环境 0x03 Api接口 0x04 服务端开发 需求分析 搜索服务注册Eureka 搜索服务客户端 自定义错误代码 Service Controller 测试 0x05 前端开发 需求分析 api方法 配置代理 视频播放页面 简单的测试 完整的测试 1、上传文件 一些问题 ~~方案1:删除本地分块文件重新尝试上传~~ 方案2:检查前端提交的MD5值是否正确 2、为课程计划选择媒资信息 3、前端门户测试 四、待完善的一些功能 😁 认识作者 一、学习页面:查询课程计划 0x01 需求分析 到目前为止,我们已可以编辑课程计划信息并上传课程视频,下一步我们要实现在线学习页面动态读取章节对应的视频并进行播放。在线学习页面所需要的信息有两类: 课程计划信息 课程学习信息(视频地址、学习进度等) 如下图: 在线学习集成媒资管理的需求如下: 1、在线学习页面显示课程计划 2、点击课程计划播放该课程计划对应的视频 本章节实现学习页面动态显示课程计划,进入不同课程的学习页面右侧动态显示当前课程的课程计划。 0x02 Api接口 课程计划信息从哪里获取? 在课程发布完成后会自动发布到一个 course_pub 的表中,logstash 会自动将课程发布后的信息自动采集到 ES 索引库中,这些信息也包含课程计划信息。 所以考虑性能要求,课程发布后对课程的查询统一从 ES 索引库中查询。 前端通过请求 搜索服务 获取课程信息,需要单独在 搜索服务 中定义课程信息查询接口。 本接口接收课程id,查询课程所有信息返回给前端。 我们在搜素服务 API 下添加以下方法 @ApiOperation("根据id搜索课程发布信息")public Map<String,CoursePub> getdetail(String id); 返回的课程信息为 json 结构:key 为课程id,value 为课程内容。 0x03 服务端开发 在搜索服务中开发查询课程信息接口。 Controller 在搜素服务下添加以下方法 / 根据id搜索课程发布信息 @param id 课程id @return JSON数据/@Override@GetMapping("/getdetail/{id}")public Map<String, CoursePub> getdetail(@PathVariable("id")String id) {return esCourseService.getdetail(id);} Service / 根据id搜索课程发布信息 @param id 课程id @return JSON数据/public Map<String, CoursePub> getdetail(String id) {//设置索引SearchRequest searchRequest = new SearchRequest(es_index);//设置类型searchRequest.types(es_type);//创建搜索源对象SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//设置查询条件,根据id进行查询searchSourceBuilder.query(QueryBuilders.termQuery("id",id));//这里不使用source的原字段过滤,查询所有字段// searchSourceBuilder.fetchSource(new String[]{"name", "grade", "charge","pic"}, newString[]{});//设置搜索源对象searchRequest.source(searchSourceBuilder);//执行搜索SearchResponse searchResponse = null;try {searchResponse = restHighLevelClient.search(searchRequest);} catch (IOException e) {e.printStackTrace();}//获取搜索结果SearchHits hits = searchResponse.getHits();SearchHit[] searchHits = hits.getHits(); //获取最优结果Map<String,CoursePub> map = new HashMap<>();for (SearchHit hit: searchHits) {//从搜索结果中取值并添加到coursePub对象Map<String, Object> sourceAsMap = hit.getSourceAsMap();String courseId = (String) sourceAsMap.get("id");String name = (String) sourceAsMap.get("name");String grade = (String) sourceAsMap.get("grade");String charge = (String) sourceAsMap.get("charge");String pic = (String) sourceAsMap.get("pic");String description = (String) sourceAsMap.get("description");String teachplan = (String) sourceAsMap.get("teachplan");CoursePub coursePub = new CoursePub();coursePub.setId(courseId);coursePub.setName(name);coursePub.setPic(pic);coursePub.setGrade(grade);coursePub.setTeachplan(teachplan);coursePub.setDescription(description);//设置map对象map.put(courseId,coursePub);}return map;} 测试 使用 swagger-ui 或 postman 测试查询课程信息接口。 0x04 前端开发 配置NGINX虚拟主机 学习中心的二级域名为 ucenter.xuecheng.com ,我们在 nginx 中配置 ucenter 虚拟主机。 学成网用户中心server {listen 80;server_name ucenter.xuecheng.com;个人中心location / {proxy_pass http://ucenter_server_pool;} } 前端ucenterupstream ucenter_server_pool{server 127.0.0.1:7081 weight=10;server 127.0.0.1:13000 weight=10;} 在学习中心要调用搜索的 API,使用 Nginx 解决代理,如下图: 在 ucenter 虚拟主机下配置搜索 Api 代理路径 后台搜索(公开api)upstream search_server_pool{server 127.0.0.1:40100 weight=10;} 学成网用户中心server {listen 80;server_name ucenter.xuecheng.com;个人中心location / {proxy_pass http://ucenter_server_pool;}后端搜索服务location /openapi/search/ {proxy_pass http://search_server_pool/search/;} } 前端 API 方法 在学习中心 xc-ui-pc-leanring 对课程信息的查询属于基础常用功能,所以我们将课程查询的 api 方法定义在base 模块下,如下图: 在system.js 中定义课程查询方法: import http from './public'export const course_view = id => {return http.requestGet('/openapi/search/course/getdetail/'+id);} 前端 API 方法调用 在 learning_video.vue 页面中调用课程信息查询接口得到课程计划,将课程计划json 串转成对象。 xc-ui-pc-leanring/src/module/course/page/learning_video.vue 1、定义视图 课程计划 <!--课程计划部分代码--><div class="navCont"><div class="course-weeklist"><div class="nav nav-stacked" v-for="(teachplan_first, index) in teachplanList"><div class="tit nav-justified text-center"><i class="pull-left glyphicon glyphicon-th-list"></i>{ {teachplan_first.pname} }<i class="pull-right"></i></div><li v-if="teachplan_first.children!=null" v-for="(teachplan_second, index) in teachplan_first.children"><i class="glyphicon glyphicon-check"></i><a :href="url" @click="study(teachplan_second.id)">{ {teachplan_second.pname} }</a></li><!-- <div class="tit nav-justified text-center"><i class="pull-left glyphicon glyphicon-th-list"></i>第一章<i class="pull-right"></i></div><li ><i class="glyphicon glyphicon-check"></i><a :href="url" >第一节</a></li>--><!--<li><i class="glyphicon glyphicon-unchecked"></i>为什么分为A、B、C部分</li>--></div></div></div> 课程名称 <div class="top text-center">{ {coursename} }</div> 定义数据对象 data() {return {url:'',//当前urlcourseId:'',//课程idchapter:'',//章节Idcoursename:'',//课程名称coursepic:'',//课程图片teachplanList:[],//课程计划playerOptions: {//播放参数autoplay: false,controls: true,sources: [{type: "application/x-mpegURL",src: ''}]},} } 在 created 钩子方法中获取课程信息 created(){//当前请求的urlthis.url = window.location//课程idthis.courseId = this.$route.params.courseId//章节idthis.chapter = this.$route.params.chapter//查询课程信息systemApi.course_view(this.courseId).then((view_course)=>{if(!view_course || !view_course[this.courseId]){this.$message.error("获取课程信息失败,请重新进入此页面!")return ;} let courseInfo = view_course[this.courseId]console.log(courseInfo)this.coursename = courseInfo.nameif(courseInfo.teachplan){let teachplan = JSON.parse(courseInfo.teachplan);this.teachplanList = teachplan.children;} })}, 测试 在浏览器请求:http://ucenter.xuecheng.com//learning/4028e581617f945f01617f9dabc40000/0 4028e581617f945f01617f9dabc40000:第一个参数为课程 id,测试时从 ES索引库找一个课程 id 0:第二个参数为课程计划 id,此参数用于点击课程计划播放视频。 如果出现跨域问题,但是确定已经配置了跨域,请尝试结束所以 nginx.exe 的进程 和 清空浏览器缓存。 如果还没有解决?重启电脑试试。 二、学习页面:获取视频播放地址 0x01 需求分析 用户进入在线学习页面,点击课程计划将播放该课程计划对应的教学视频。 业务流程如下: 业务流程说明: 1、用户进入在线学习页面,页面请求搜索服务获取课程信息(包括课程计划信息)并且在页面展示。 2、在线学习请求学习服务获取视频播放地址。 3、学习服务校验当前用户是否有权限学习,如果没有权限学习则提示用户。 4、学习服务校验通过,请求搜索服务获取课程媒资信息。 5、搜索服务请求ElasticSearch获取课程媒资信息。 为什么要请求 ElasticSearch 查询课程媒资信息? 出于性能的考虑,公开查询课程信息从搜索服务查询,分摊 mysql 数据库的访问压力。 什么时候将课程媒资信息存储到 ElasticSearch 中? 课程媒资信息是在课程发布的时候存入 ElasticSearch,因为课程发布后课程信息将基本不再修改。 0x02 课程发布:储存媒资信息 需求分析 课程媒资信息是在课程发布的时候存入 ElasticSearch 索引库,因为课程发布后课程信息将基本不再修改,具体的业务流程如下。 1、课程发布,向课程媒资信息表写入数据。 1)根据课程 id 删除 teachplanMediaPub 中的数据 2)根据课程 id 查询 teachplanMedia 数据 3)将查询到的 teachplanMedia 数据插入到 teachplanMediaPub 中 2、Logstash 定时扫描课程媒资信息表,并将课程媒资信息写入索引库。 数据模型 在 xc_course 数据库创建课程计划媒资发布表: CREATE TABLE teachplan_media_pub (teachplan_id varchar(32) NOT NULL COMMENT '课程计划id',media_id varchar(32) NOT NULL COMMENT '媒资文件id',media_fileoriginalname varchar(128) NOT NULL COMMENT '媒资文件的原始名称',media_url varchar(256) NOT NULL COMMENT '媒资文件访问地址',courseid varchar(32) NOT NULL COMMENT '课程Id',timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT'logstash使用',PRIMARY KEY (teachplan_id)) ENGINE=InnoDB DEFAULT CHARSET=utf8 数据模型类如下: package com.xuecheng.framework.domain.course;import lombok.Data;import lombok.ToString;import org.hibernate.annotations.GenericGenerator;import javax.persistence.;import java.io.Serializable;import java.util.Date;@Data@ToString@Entity@Table(name="teachplan_media_pub")@GenericGenerator(name = "jpa-assigned", strategy = "assigned")public class TeachplanMediaPub implements Serializable {private static final long serialVersionUID = -916357110051689485L;@Id@GeneratedValue(generator = "jpa-assigned")@Column(name="teachplan_id")private String teachplanId;@Column(name="media_id")private String mediaId;@Column(name="media_fileoriginalname")private String mediaFileOriginalName;@Column(name="media_url")private String mediaUrl;@Column(name="courseid")private String courseId;@Column(name="timestamp")private Date timestamp;//时间戳} Dao 创建 TeachplanMediaPub 表的 Dao,向 TeachplanMediaPub 存储信息采用先删除该课程的媒资信息,再添加该课程的媒资信息,所以这里定义根据课程 id 删除课程计划媒资方法: public interface TeachplanMediaPubRepository extends JpaRepository<TeachplanMediaPub, String> {//根据课程id删除课程计划媒资信息long deleteByCourseId(String courseId);} 从TeachplanMedia查询课程计划媒资信息 //从TeachplanMedia查询课程计划媒资信息public interface TeachplanMediaRepository extends JpaRepository<TeachplanMedia, String> {List<TeachplanMedia> findByCourseId(String courseId);} Service 编写保存课程计划媒资信息方法,并在课程发布时调用此方法。 1、保存课程计划媒资信息方法 本方法采用先删除该课程的媒资信息,再添加该课程的媒资信息,在 CourseService 下定义该方法 //保存课程计划媒资信息private void saveTeachplanMediaPub(String courseId){//查询课程媒资信息List<TeachplanMedia> byCourseId = teachplanMediaRepository.findByCourseId(courseId);if(byCourseId == null) return; //没有查询到媒资数据则直接结束该方法//将课程计划媒资信息储存到待索引表//删除原有的索引信息teachplanMediaPubRepository.deleteByCourseId(courseId);//一个课程可能会有多个媒资信息,遍历并使用list进行储存List<TeachplanMediaPub> teachplanMediaPubList = new ArrayList<>();for (TeachplanMedia teachplanMedia: byCourseId) {TeachplanMediaPub teachplanMediaPub = new TeachplanMediaPub();BeanUtils.copyProperties(teachplanMedia, teachplanMediaPub);teachplanMediaPubList.add(teachplanMediaPub);}//保存所有信息teachplanMediaPubRepository.saveAll(teachplanMediaPubList);} 2、课程发布时调用此方法 修改课程发布的 coursePublish 方法: ....//保存课程计划媒资信息到待索引表saveTeachplanMediaPub(courseId);//页面urlString pageUrl = cmsPostPageResult.getPageUrl();return new CoursePublishResult(CommonCode.SUCCESS,pageUrl);..... 测试 测试课程发布后是否成功将课程媒资信息存储到 teachplan_media_pub 中,测试流程如下: 1、指定一个课程 2、为课程计划添加课程媒资 3、执行课程发布 4、观察课程计划媒资信息是否存储至 teachplan_media_pub 中 注意:由于此测试仅用于测试发布课程计划媒资信息的功能,可暂时将 cms页面发布的功能暂时屏蔽,提高测试效率。 测试结果如下 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vrzs5589-1595567273126)(https://qnoss.codeyee.com/20200704_15/image7)] 0x03 Logstash:扫描课程计划媒资 Logstash 定时扫描课程媒资信息表,并将课程媒资信息写入索引库。 创建索引 1、创建 xc_course_media 索引 2、并向此索引创建如下映射 POST: http://localhost:9200/xc_course_media/doc/_mapping {"properties" : {"courseid" : {"type" : "keyword"},"teachplan_id" : {"type" : "keyword"},"media_id" : {"type" : "keyword"},"media_url" : {"index" : false,"type" : "text"},"media_fileoriginalname" : {"index" : false,"type" : "text"} }} 索引创建成功 创建模板文件 在 logstach 的 config 目录文件 xc_course_media_template.json 文件路径为 %ES_ROOT_DIR%/logstash6.8.8/config/xc_course_media_template.json %ES_ROOT_DIR% 为 ElasticSearch 和 logstash 的安装目录 内容如下: {"mappings" : {"doc" : {"properties" : {"courseid" : {"type" : "keyword"},"teachplan_id" : {"type" : "keyword"},"media_id" : {"type" : "keyword"},"media_url" : {"index" : false,"type" : "text"},"media_fileoriginalname" : {"index" : false,"type" : "text"} }},"template" : "xc_course_media"} } 配置 mysql.conf 在logstash的 config 目录下配置 mysql_course_media.conf 文件供 logstash 使用,logstash 会根据 mysql_course_media.conf 文件的配置的地址从 MySQL 中读取数据向 ES 中写入索引。 参考https://www.elastic.co/guide/en/logstash/current/plugins-inputs-jdbc.html 配置输入数据源和输出数据源。 input {stdin {} jdbc {jdbc_connection_string => "jdbc:mysql://localhost:3306/xc_course?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC" 数据库信息jdbc_user => "root"jdbc_password => "123123" MYSQL 驱动地址,修改为maven仓库对应的位置jdbc_driver_library => "D:/soft/apache-maven-3.5.4/repository/mysql/mysql-connector-java/5.1.40/mysql-connector-java-5.1.40.jar" the name of the driver class for mysqljdbc_driver_class => "com.mysql.jdbc.Driver"jdbc_paging_enabled => "true"jdbc_page_size => "50000"要执行的sql文件statement_filepath => "/conf/course.sql"statement => "select from teachplan_media_pub where timestamp > date_add(:sql_last_value,INTERVAL 8 HOUR)"定时配置schedule => " "record_last_run => truelast_run_metadata_path => "D:/soft/elasticsearch/logstash-6.8.8/config/xc_course_media_metadata"} } output {elasticsearch {ES的ip地址和端口hosts => "localhost:9200"hosts => ["localhost:9200","localhost:9202","localhost:9203"]ES索引库名称index => "xc_course_media"document_id => "%{teachplan_id}"document_type => "doc"template => "D:/soft/elasticsearch/logstash-6.8.8/config/xc_course_media_template.json"template_name =>"xc_course_media"template_overwrite =>"true"} stdout {日志输出codec => json_lines} } 启动 logstash.bat 启动 logstash.bat 采集 teachplan_media_pub 中的数据,向 ES 写入索引。 logstash.bat -f ../config/mysql_course_media.conf 课程发布成功后,Logstash 会自动参加 teachplan_media_pub 表中新增的数据,效果如下 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ILPBxfXi-1595567273134)(https://qnoss.codeyee.com/20200704_15/image10)] Logstash多实例运行 由于之前我们还启动了一个 Logstash 对课程的发布信息进行采集,所以如果想两个 logstash 实例同时运行,因为每个实例都有一个.lock文件,所以不能使用同一个目录来存放数据,所以我们需要使用 --path.data= 为每个实例指定单独的数据目录,具体的代码如下: 该配置是在windows下进行的 课程发布实例 logstash_start_course_pub.bat @title logstash in course_publogstash.bat -f ..\config\mysql.conf --path.data=../data/course_pub 课程计划媒体发布实例 logstash_start_teachplan_media.bat @title logstash i n teachplan_media_publogstash.bat -f ../config/mysql_course_media.conf --path.data=../data/teachplan_media/ 同时运行效果如下 0x04 搜素服务:查询课程媒资接口 需求分析 搜索服务 提供查询课程媒资接口,此接口供学习服务调用。 Api接口定义 @ApiOperation("根据课程计划查询媒资信息")public TeachplanMediaPub getmedia(String teachplanId); Service 1、配置课程计划媒资索引库等信息 在 application.yml 中配置 xuecheng:elasticsearch:hostlist: ${eshostlist:127.0.0.1:9200} 多个结点中间用逗号分隔course:index: xc_coursetype: docsource_field: id,name,grade,mt,st,charge,valid,pic,qq,price,price_old,status,studymodel,teachmode,expires,pub_time,start_time,end_timemedia:index: xc_course_mediatype: docsource_field: courseid,media_id,media_url,teachplan_id,media_fileoriginalname 2、service 方法开发 在 课程搜索服务 中定义课程媒资查询接口,为了适应后续需求,service 参数定义为数组,可一次查询多个课程计划的媒资信息。 / 根据一个或者多个课程计划id查询媒资信息 @param teachplanIds 课程id @return QueryResponseResult/public QueryResponseResult<TeachplanMediaPub> getmedia(String [] teachplanIds){//设置索引SearchRequest searchRequest = new SearchRequest(media_index);//设置类型searchRequest.types(media_type);//创建搜索源对象SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//源字段过滤String[] media_index_arr = media_field.split(",");searchSourceBuilder.fetchSource(media_index_arr, new String[]{});//查询条件,根据课程计划id查询(可以传入多个课程计划id)searchSourceBuilder.query(QueryBuilders.termsQuery("teachplan_id", teachplanIds));searchRequest.source(searchSourceBuilder);SearchResponse searchResponse = null;try {searchResponse = restHighLevelClient.search(searchRequest);} catch (IOException e) {e.printStackTrace();}//获取结果SearchHits hits = searchResponse.getHits();long totalHits = hits.getTotalHits();SearchHit[] searchHits = hits.getHits();//数据列表List<TeachplanMediaPub> teachplanMediaPubList = new ArrayList<>();for(SearchHit hit:searchHits){TeachplanMediaPub teachplanMediaPub =new TeachplanMediaPub();Map<String, Object> sourceAsMap = hit.getSourceAsMap();//取出课程计划媒资信息String courseid = (String) sourceAsMap.get("courseid");String media_id = (String) sourceAsMap.get("media_id");String media_url = (String) sourceAsMap.get("media_url");String teachplan_id = (String) sourceAsMap.get("teachplan_id");String media_fileoriginalname = (String) sourceAsMap.get("media_fileoriginalname");teachplanMediaPub.setCourseId(courseid);teachplanMediaPub.setMediaUrl(media_url);teachplanMediaPub.setMediaFileOriginalName(media_fileoriginalname);teachplanMediaPub.setMediaId(media_id);teachplanMediaPub.setTeachplanId(teachplan_id);//将对象加入到列表中teachplanMediaPubList.add(teachplanMediaPub);}//构建返回课程媒资信息对象QueryResult<TeachplanMediaPub> queryResult = new QueryResult<>();queryResult.setList(teachplanMediaPubList);queryResult.setTotal(totalHits);return new QueryResponseResult<TeachplanMediaPub>(CommonCode.SUCCESS,queryResult);} Controller / 根据课程计划id搜索发布后的媒资信息 @param teachplanId @return/@GetMapping(value="/getmedia/{teachplanId}")@Overridepublic TeachplanMediaPub getmedia(@PathVariable("teachplanId") String teachplanId) {//为了service的拓展性,所以我们service接收的是数组作为参数,以便后续开发查询多个ID的接口String[] teachplanIds = new String[]{teachplanId};//通过service查询ES获取课程媒资信息QueryResponseResult<TeachplanMediaPub> mediaPubQueryResponseResult = esCourseService.getmedia(teachplanIds);QueryResult<TeachplanMediaPub> queryResult = mediaPubQueryResponseResult.getQueryResult();if(queryResult!=null&& queryResult.getList()!=null&& queryResult.getList().size()>0){//返回课程计划对应课程媒资return queryResult.getList().get(0);} return new TeachplanMediaPub();} 测试 使用 swagger-ui 和 postman 测试课程媒资查询接口。 三、在线学习:接口开发 0x01 需求分析 根据下边的业务流程,本章节完成前端学习页面请求学习服务获取课程视频地址,并自动播放视频。 0x02 搭建开发环境 1、创建数据库 创建 xc_learning 数据库,学习数据库将记录学生的选课信息、学习信息。 导入:资料/xc_learning.sql 2、创建学习服务工程 参考课程管理服务工程结构,创建学习服务工程: 导入:资料/xc-service-learning.zip 项目工程结构如下 0x03 Api接口 此 api 接口是课程学习页面请求学习服务获取课程学习地址。 定义返回值类型: package com.xuecheng.framework.domain.learning.response;import com.xuecheng.framework.model.response.ResponseResult;import com.xuecheng.framework.model.response.ResultCode;import lombok.Data;import lombok.NoArgsConstructor;import lombok.ToString;@Data@ToString@NoArgsConstructorpublic class GetMediaResult extends ResponseResult {public GetMediaResult(ResultCode resultCode, String fileUrl) {super(resultCode);this.fileUrl = fileUrl;}//媒资文件播放地址private String fileUrl;} 定义接口,学习服务根据传入课程 ID、章节 Id(课程计划 ID)来取学习地址。 @Api(value = "录播课程学习管理",description = "录播课程学习管理")public interface CourseLearningControllerApi {@ApiOperation("获取课程学习地址")public GetMediaResult getMediaPlayUrl(String courseId,String teachplanId);} 0x04 服务端开发 需求分析 学习服务根据传入课程ID、章节Id(课程计划ID)请求搜索服务获取学习地址。 搜索服务注册Eureka 学习服务要调用搜索服务查询课程媒资信息,所以需要将搜索服务注册到 eureka 中。 1、查看服务名称是否为 xc-service-search 注意修改application.xml中的服务名称:spring:application:name: xc‐service‐search 2、配置搜索服务的配置文件 application.yml,加入 Eureka 配置 如下: eureka:client:registerWithEureka: true 服务注册开关fetchRegistry: true 服务发现开关serviceUrl: Eureka客户端与Eureka服务端进行交互的地址,多个中间用逗号分隔defaultZone: ${EUREKA_SERVER:http://localhost:50101/eureka/,http://localhost:50102/eureka/}instance:prefer-ip-address: true 将自己的ip地址注册到Eureka服务中ip-address: ${IP_ADDRESS:127.0.0.1}instance-id: ${spring.application.name}:${server.port} 指定实例idribbon:MaxAutoRetries: 2 最大重试次数,当Eureka中可以找到服务,但是服务连不上时将会重试,如果eureka中找不到服务则直接走断路器MaxAutoRetriesNextServer: 3 切换实例的重试次数OkToRetryOnAllOperations: false 对所有操作请求都进行重试,如果是get则可以,如果是post,put等操作没有实现幂等的情况下是很危险的,所以设置为falseConnectTimeout: 5000 请求连接的超时时间ReadTimeout: 6000 请求处理的超时时间 3、添加 eureka 依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring‐cloud‐starter‐netflix‐eureka‐client</artifactId></dependency> 4、修改启动类,在class上添加如下注解: @EnableDiscoveryClient 搜索服务客户端 在 学习服务 创建搜索服务的客户端接口,此接口会生成代理对象,调用搜索服务: package com.xuecheng.learning.client;import com.xuecheng.framework.domain.course.TeachplanMediaPub;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;@FeignClient(value = "xc‐service‐search")public interface CourseSearchClient {@GetMapping(value="/getmedia/{teachplanId}")public TeachplanMediaPub getmedia(@PathVariable("teachplanId") String teachplanId);} 自定义错误代码 我们在 com.xuecheng.framework.domain.learning.response 包下自定义一个错误消息模型 package com.xuecheng.framework.domain.learning.response;import com.xuecheng.framework.model.response.ResultCode;import lombok.ToString;@ToStringpublic enum LearningCode implements ResultCode {LEARNING_GET_MEDIA_ERROR(false,23001,"学习中心获取媒资信息错误!");//操作代码boolean success;//操作代码int code;//提示信息String message;private LearningCode(boolean success, int code, String message){this.success = success;this.code = code;this.message = message;}@Overridepublic boolean success() {return success;}@Overridepublic int code() {return code;}@Overridepublic String message() {return message;} } 该消息模型基于 ResultCode 来实现,代码如下 package com.xuecheng.framework.model.response;/ Created by mrt on 2018/3/5. 10000-- 通用错误代码 22000-- 媒资错误代码 23000-- 用户中心错误代码 24000-- cms错误代码 25000-- 文件系统/public interface ResultCode {//操作是否成功,true为成功,false操作失败boolean success();//操作代码int code();//提示信息String message(); 从 ResultCode 中我们可以看出,我们约定了用户中心的错误代码使用 23000,所以我们定义的一些错误信息的代码就从 23000 开始计数。 Service 在学习服务中定义 service 方法,此方法远程请求课程管理服务、媒资管理服务获取课程学习地址。 package com.xuecheng.learning.service.impl;import com.netflix.discovery.converters.Auto;import com.xuecheng.framework.domain.course.TeachplanMediaPub;import com.xuecheng.framework.domain.learning.response.GetMediaResult;import com.xuecheng.framework.exception.ExceptionCast;import com.xuecheng.framework.model.response.CommonCode;import com.xuecheng.learning.client.CourseSearchClient;import com.xuecheng.learning.service.LearningService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class LearningServiceImpl implements LearningService {@AutowiredCourseSearchClient courseSearchClient;/ 远程调用搜索服务获取已发布媒体信息中的url @param courseId 课程id @param teachplanId 媒体信息id @return/@Overridepublic GetMediaResult getMediaPlayUrl(String courseId, String teachplanId) {//校验学生权限,是否已付费等//远程调用搜索服务进行查询媒体信息TeachplanMediaPub mediaPub = courseSearchClient.getmedia(teachplanId);if(mediaPub == null) ExceptionCast.cast(CommonCode.FAIL);return new GetMediaResult(CommonCode.SUCCESS, mediaPub.getMediaUrl());} } Controller 调用 service 根据课程计划 id 查询视频播放地址: @RestController@RequestMapping("/learning/course")public class CourseLearningController implements CourseLearningControllerApi {@AutowiredLearningService learningService;@Override@GetMapping("/getmedia/{courseId}/{teachplanId}")public GetMediaResult getMediaPlayUrl(@PathVariable String courseId, @PathVariable String teachplanId) {//获取课程学习地址return learningService.getMedia(courseId, teachplanId);} } 测试 使用 swagger-ui 或postman 测试学习服务查询课程视频地址接口。 0x05 前端开发 需求分析 需要在学习中心前端页面需要完成如下功能: 1、进入课程学习页面需要带上 课程 Id参数及课程计划Id的参数,其中 课程 Id 参数必带,课程计划 Id 可以为空。 2、进入页面根据 课程 Id 取出该课程的课程计划显示在右侧。 3、进入页面后判断如果请求参数中有课程计划 Id 则播放该章节的视频。 4、进入页面后判断如果 课程计划id 为0则需要取出本课程第一个 课程计划的Id,并播放第一个课程计划的视频。 进入到模块 xc-ui-pc-leanring/src/module/course api方法 let sysConfig = require('@/../config/sysConfig')let apiUrl = sysConfig.xcApiUrlPre;/获取播放地址/export const get_media = (courseId,chapter) => {return http.requestGet(apiUrl+'/api/learning/course/getmedia/'+courseId+'/'+chapter);} 配置代理 在 Nginx 中的 ucenter.xuecheng.com 虚拟主机中配置 /api/learning/ 的路径转发,此url 请转发到学习服务。 学习服务upstream learning_server_pool{server 127.0.0.1:40600 weight=10;}学成网用户中心server {listen 80;server_name ucenter.xuecheng.com;个人中心location / {proxy_pass http://ucenter_server_pool;}后端搜索服务location /openapi/search/ {proxy_pass http://search_server_pool/search/; }学习服务location ^~ /api/learning/ {proxy_pass http://learning_server_pool/learning/;} } 视频播放页面 1、如果传入的课程计划id为0则取出第一个课程计划id 在 created 钩子方法中完成 created(){//当前请求的urlthis.url = window.location//课程idthis.courseId = this.$route.params.courseId//章节idthis.chapter = this.$route.params.chapter//查询课程信息systemApi.course_view(this.courseId).then((view_course)=>{if(!view_course || !view_course[this.courseId]){this.$message.error("获取课程信息失败,请重新进入此页面!")return ;}let courseInfo = view_course[this.courseId]console.log(courseInfo)this.coursename = courseInfo.nameif(courseInfo.teachplan){console.log("准备开始播放视频")let teachplan = JSON.parse(courseInfo.teachplan);this.teachplanList = teachplan.children;//开始学习if(this.chapter == "0" || !this.chapter){//取出第一个教学计划this.chapter = this.getFirstTeachplan();console.log("第一个教学计划id为 ",this.chapter);this.study(this.chapter);}else{this.study(this.chapter);} }})}, 取出第一个章节 id,用户未输入课程计划 id 或者输入为 0 时,播放第一个。 //取出第一个章节getFirstTeachplan(){for(var i=0;i<this.teachplanList.length;i++){let firstTeachplan = this.teachplanList[i];//如果当前children存在,则取出第一个返回if(firstTeachplan.children && firstTeachplan.children.length>0){let secondTeachplan = firstTeachplan.children[0];return secondTeachplan.id;} }return ;}, 开始学习: //开始学习study(chapter){// 获取播放地址courseApi.get_media(this.courseId,chapter).then((res)=>{if(res.success){let fileUrl = sysConfig.videoUrl + res.fileUrl//播放视频this.playvideo(fileUrl)}else if(res.message){this.$message.error(res.message)}else{this.$message.error("播放视频失败,请刷新页面重试")} }).catch(res=>{this.$message.error("播放视频失败,请刷新页面重试")});}, 2、点击右侧课程章节切换播放 在原有代码基础上添加 click 事件,点击调用开始学习方法(study)。 <li v‐if="teachplan_first.children!=null" v‐for="(teachplan_second, index) inteachplan_first.children"><i class="glyphicon glyphicon‐check"></i><a :href="url" @click="study(teachplan_second.id)">{ {teachplan_second.pname} }</a></li> 3、地址栏路由url变更 这里需要注意一个问题,在用户点击课程章节切换播放时,地址栏的 url 也应该同步改变为当前所选择的课程计划 id 4、在线学习按钮 将 learnstatus 默认更改为 1,这样就能显示出马上学习的按钮,方便我们后续的集成测试。 文件路径为 xc-ui-pc-static-portal/include/course_detail_dynamic.html 部分代码块如下 <script>var body= new Vue({ //创建一个Vue的实例el: "body", //挂载点是id="app"的地方data: {editLoading: false,title:'测试',courseId:'',charge:'',//203001免费,203002收费learnstatus: 1 ,//课程状态,1:马上学习,2:立即报名、3:立即购买course:{},companyId:'template',company_stat:[],course_stat:{"s601001":"","s601002":"","s601003":""} }, 简单的测试 访问在线学习页面:http://ucenter.xuecheng.com//learning/课程id/课程计划id 通过 url 传入两个参数:课程id 和 课程计划id 如果没有课程计划则传入0 测试项目如下: 1、传入正确的课程id、课程计划id,自动播放本章节的视频 2、传入正确的课程id、课程计划id传入0,自动播放第一个视频 3、传入错误的课程id 或 课程计划id,提示错误信息。 4、通过右侧章节目录切换章节及播放视频。 访问: http://ucenter.xuecheng.com//learning/4028e58161bcf7f40161bcf8b77c0000/4028e58161bd18ea0161bd1f73190008 传入正确的课程id、课程计划id,自动播放本章节的视频 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ef0xxym7-1595567273153)(https://qnoss.codeyee.com/20200704_15/image17)] 传入正确的课程id、课程计划id传入0,自动播放第一个视频 访问 http://ucenter.xuecheng.com//learning/4028e58161bcf7f40161bcf8b77c0000/0 识别出第一个课程计划的 id 需要注意的是这里的 chapter 参数是我自己在 study 函数里加上去的,可以忽略。 传入错误的课程id或课程计划id,提示错误信息。 通过右侧章节目录切换章节及播放视频。 点击章节即可播放,但是点击制定章节后 url 没有发生改变,这个问题暂时还没有解决,关注笔记后面的内容。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TOGdxwb4-1595567273158)(https://qnoss.codeyee.com/20200704_15/image20)] 完整的测试 准备工作 启动 RabbitMQ,启动 Logstash、ElasticSearch 建议把所有后端服务都开起来 启动 前端静态门户、启动 nginx 、启动课程管理前端 我们整理一下测试的流程 上传两个媒资视频文件,用于测试 进入到课程管理,为课程计划选择媒资信息 发布课程,等待 logstash 将数据采集到 ElasticSearch 的索引库中 进入学成网主页,点击课程,进入到搜索门户页面 搜索课程,进入到课程详情页面 点击开始学习,进入到课程学习页面,选择课程计划中的一个章节进行学习。 1、上传文件 首先我们使用之前开发的媒资管理模块,上传两个视频文件用于测试。 第一个文件上传成功 一些问题 在上传第二个文件时,发生了错误,我们来检查一下问题出在了哪里 在媒体服务的控制台中可以看到,在 mergeChunks 方法在校验文件 md5 时候抛出了异常 我们在 MD5 校验这里打个断点,重新上传文件,分析一下问题所在。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OpEMZGI8-1595567273166)(https://qnoss.codeyee.com/20200704_15/image23)] 单步调试后发现,合并文件后的MD5值与用户上传的源文件值不相等 方案1:删除本地分块文件重新尝试上传 考虑到可能是在用户上传完 视频的分块文件时发生了一些问题,导致合并文件后与源文件的大小不等,导致MD5也不相同,这里我们把这个视频上传到本地的文件全部删除,在媒资上传页面重新上传文件。 对比所有分块文件的字节大小和本地源文件的大小,完全是相等的 删除所有文件后重新上传,md5值还是不等,考虑从调试一下文件合并的代码。 方案2:检查前端提交的MD5值是否正确 在查阅是否有其他的MD5值获取方案时,发现了一个使用 windows 本地命令获取文件MD5值的方法 certutil -hashfile .\19-在线学习接口-集成测试.avi md5 惊奇的发现,TM的原来是前端那边转换的MD5值不正确,后端这边是没有问题的。 从前面的图可以看出,本地和后端转换的都是以一个 f6f0 开头的MD5值 那么问题就出现在前端了,还需要花一些时间去分析一下,这里暂时就先告一段落,因为上传了几个文件测试中只有这一个文件出现了问题。 2、为课程计划选择媒资信息 进入到一个课程的管理页面 http://localhost:12000//course/manage/baseinfo/4028e58161bcf7f40161bcf8b77c0000 将刚才我们上传的媒资文件的信息和课程计划绑定 选择效果如下 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-epKaqzCD-1595567273178)(https://qnoss.codeyee.com/20200704_15/image29)] 2、发布课程,等待 logstash 从 course_pub 以及 teachplan_media_pub 表中采集数据到 ElasticSearch 当中 发布成功后,我们可以从 teachplan_media_pub 表中看到刚才我们发布的媒资信息 再观察 Logstash 的控制台,发现两个 Logstash 的实例都对更新的课程发布信息进行了采集 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hTUve2ik-1595567273183)(https://qnoss.codeyee.com/20200704_15/image32)] 3、前端门户测试 打开我们的门户主站 http://www.xuecheng.com/ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4wZe9R84-1595567273185)(https://qnoss.codeyee.com/20200704_15/image33)] 点击导航栏的课程,进入到我们的搜索门户页面 如果无法进入到搜索门户,请检查你的 xc-ui-pc-portal 前端工程是否已经启动 进入到搜索门户后,可以看到一些初始化时搜索的课程数据,默认是搜索第一页的数据,每页2个课程。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BJ1AKoJb-1595567273187)(https://qnoss.codeyee.com/20200704_15/image34)] 我们可以测试搜索一下前面我们选择媒资信息时所用的课程 点击课程,进入到课程详情页面,然后再点击开始学习。 点击马上学习后,会进入到该课程的在线学习页面,默认自动播放我们第一个课程计划中的视频。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tcuLWnf2-1595567273193)(https://qnoss.codeyee.com/20200704_15/image37)] 我们可以在右侧的目录中选择第二个课程计划,会自动播放所选的课程计划所对应的媒资视频播放地址,该 播放地址正是我们刚才通过 Logstash 自动采集到 ElasticSearch 的索引信息,效果图如下 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cvi9Dr0Y-1595567273195)(https://qnoss.codeyee.com/20200704_15/image38)] 四、待完善的一些功能 课程发布前,校验课程计划里面是否包含二级课程计划 课程发布前,校验课程计划信息里面是否全部包含媒资信息 删除媒资信息,并且同步删除ES中的索引 在获取该课程的播放地址时校验用户的合法、 在线学习页面,点击右侧目录中的课程计划同时改变url中的课程计划地址 视频文件 19-在线学习接口-集成测试.avi 前端上传时提交的MD5值不正确 😁 认识作者 作者:👦 LCyee ,全干型代码🐕 自建博客:https://www.codeyee.com 记录学习以及项目开发过程中的笔记与心得,记录认知迭代的过程,分享想法与观点。 CSDN 博客:https://blog.csdn.net/codeyee 记录和分享一些开发过程中遇到的问题以及解决的思路。 欢迎加入微服务练习生的队伍,一起交流项目学习过程中的一些问题、分享学习心得等,不定期组织一起刷题、刷项目,共同见证成长。 本篇文章为转载内容。原文链接:https://blog.csdn.net/codeyee/article/details/107558901。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-12-16 12:41:01
73
转载
Docker
...术也得到了普遍应用。Docker作为容器技术的典型,已经成为了构建和部署应用程序的常用手段之一。它可以提供一种轻量级的解决办法,将应用和它们的依赖项封装到一个可移动的容器中,并在不同的环境下执行。这篇文章将介绍如何运用Docker整合应用程序。 第一步是装置Docker。在Linux或Mac系统上执行以下命令: curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh 在Windows上,需要从官网下载装置包并进行装置。装置完成后,可以执行以下命令查看版本: docker version 接下来,需要将应用程序封装为Docker镜像。Docker镜像是一个只读的文件,它包括了执行应用程序所需要的所有文件及设定。可以运用Dockerfile来规定镜像构建步骤。在文件系统中新建一个Dockerfile文件,然后编写以下内容: FROM ubuntu:latest RUN apt-get update RUN apt-get install -y python3 RUN apt-get install -y python3-pip WORKDIR /app COPY requirements.txt /app RUN pip3 install -r requirements.txt COPY . /app CMD ["python3", "app.py"] 这个Dockerfile的作用是:运用最新版本的Ubuntu作为基础镜像,然后装置Python3和pip包管理器。我们的程序源码位于/app目录下,所以我们将运行目录设置为/app。接下来,我们将应用程序的依赖项列表存储于requirements.txt文件中,并装置这些依赖项。最后,我们拷贝整个程序源码到/app目录下,并规定了应用程序的启动指令。 当我们构建这个Docker镜像时,会执行上述Dockerfile中的指令,生成包括应用程序及其依赖项的镜像。运用以下命令来创建镜像: docker build -t myapp . 其中,“myapp”是我们为此镜像赋予的名字,点号表示运用当前目录中的Dockerfile文件。 现在,我们可以在Docker容器中执行我们的应用程序了。运用以下命令来启动容器: docker run -d -p 5000:5000 myapp 其中,“-d”选项表示在后台执行容器,“-p”选项是将容器的5000端口连接至主机的5000端口。这意味着我们可以在本地浏览器中打开http://localhost:5000来访问应用程序了。 这就是运用Docker整合应用程序的基本过程,它可以简化应用程序的构建和部署过程,提高开发效率。
2023-05-14 18:00:01
553
软件工程师
转载文章
Docker Daemon , Docker Daemon是Docker系统的核心服务进程,它在后台运行并负责管理Docker容器的整个生命周期,包括创建、启动、停止和删除容器,以及与镜像仓库进行交互以下载或上传镜像。在本文中,Docker Daemon的配置文件路径根据不同运行模式(root模式和rootless模式)有所不同,默认位于\ /etc/docker/daemon.json\ 或用户主目录下的\ ~/.docker/daemon.json\ 。 TLS (Transport Layer Security) 模式 , TLS是一种用于网络通信加密的安全协议,确保在互联网上数据传输的安全性和私密性。在Docker环境中,启用TLS模式可以对Docker守护进程与客户端之间的通信进行加密,防止敏感信息被窃取或篡改。当Docker Daemon需要使用到TLS证书时,会按照特定顺序查找这些证书文件,例如优先检查命令行参数指定的证书路径,其次考虑环境变量DOCKER_CERT_PATH等。 containerd Socket (sock) , containerd是一个独立于Docker Daemon的高性能容器运行时,提供了容器的生命周期管理功能。在Docker生态系统中,containerd.sock是一个Unix Domain Socket,它作为containerd与Docker以及其他组件之间进行通信的重要接口。在文中提到的\ /run/containerd/containerd.sock\ 即为containerd服务监听的通信端点,Docker通过连接这个socket与containerd进行交互,执行如创建、启动和停止容器等操作。
2023-09-08 20:50:40
88
转载
Docker
Dockerfile编写指南:从入门到实践 1. 引言 理解Docker与Dockerfile的重要性 在数字化转型的浪潮中,Docker作为一款强大的容器化技术工具,为软件开发、测试和部署带来了革命性的改变。Dockerfile,这个家伙可是构建Docker镜像的关键“配方”,你就把它想象成一本烹饪手册,一步步手把手教Docker怎么捣鼓出一个既精确又可重复利用的应用环境。今天,咱们就一起唠唠这个超级神奇的“菜谱”——Dockerfile的编写秘籍吧! 2. Dockerfile基础 搭建你的第一个Docker镜像 首先,让我们通过一个简单的示例来揭开Dockerfile的神秘面纱: dockerfile 这是一个最基础的Dockerfile模板 FROM ubuntu:latest 我们基于最新的Ubuntu镜像开始构建 RUN apt-get update && apt-get install -y curl 在镜像内安装curl命令 CMD ["curl", "https://www.docker.com"] 设置默认启动时运行的命令 在这个例子中,我们执行了三个基本操作: - FROM 指令指定了基础镜像。 - RUN 指令用于在新创建的镜像中执行命令并提交结果。 - CMD 指令设置了容器启动后的默认执行命令。 3. Dockerfile进阶 深入理解和使用指令 3.1 COPY与ADD指令 当我们需要将宿主机的文件复制到镜像内部时,可以使用COPY或ADD指令: dockerfile COPY . /app 将当前目录下的所有内容复制到镜像的/app目录下 ADD requirements.txt /app/ 添加特定文件到镜像指定位置,并支持自动解压tar归档文件 3.2 ENV指令 设置环境变量对于配置应用程序至关重要,ENV指令允许我们在构建镜像时定义环境变量: dockerfile ENV NODE_ENV=production 3.3 WORKDIR指令 WORKDIR用来指定工作目录,后续的RUN、CMD、ENTRYPOINT等指令都将在这个目录下执行: dockerfile WORKDIR /app 3.4 EXPOSE指令 EXPOSE用于声明容器对外提供服务所监听的端口: dockerfile EXPOSE 80 443 4. 高级话题 Dockerfile最佳实践与思考 - 保持镜像精简:每次修改镜像都应尽量小且独立,遵循单一职责原则,每个镜像只做一件事并做好。 - 层叠优化:合理安排Dockerfile中的指令顺序,减少不必要的层构建,提升构建效率。 - 充分利用缓存:Docker在构建过程中会利用缓存机制,如果已有的层没有变化,则直接复用,因此,把变动可能性大的步骤放在最后能有效利用缓存加速构建。 在编写Dockerfile的过程中,我们常常会遇到各种挑战和问题,这正是探索与学习的乐趣所在。每一次动手尝试,都是我们对容器化这个理念的一次接地气的深入理解和灵活运用,就好比每敲出的一行代码,都在悄无声息地讲述着我们这群人,对于打造出那种既高效、又稳定、还能随时随地搬来搬去的应用环境,那份死磕到底、永不言弃的坚持与热爱。 所以,亲爱的开发者朋友们,不妨亲手拿起键盘,去编写属于你自己的Dockerfile,感受那种“从无到有”的创造魅力,同时也能深深体验到Docker所带来的便捷和力量。在这场编程之旅中,愿我们都能以更轻便的方式,拥抱云原生时代!
2023-08-01 16:49:40
513
百转千回_
Docker
Docker , Docker是一种开源的应用容器引擎,它通过容器化技术将应用程序及其依赖环境打包成独立、可移植的软件单元。在Docker中,每个容器都是一个轻量级、隔离的操作系统层,可以在任何支持Docker的主机上运行,确保了应用在不同环境下的一致性和可移植性。 Volumes , 在Docker中,Volumes是用于持久化存储的一种机制,允许将宿主机的文件系统与容器内部的文件系统进行挂载映射。即使容器停止或重新创建,通过Volumes机制绑定的数据也能得到持久保存,实现容器内外数据的共享和持久化存储。 Dockerfile , Dockerfile是一个文本文件,包含了一系列用于构建Docker镜像的指令集合。开发人员可以通过编写Dockerfile来定义应用程序如何被封装到Docker容器中,包括所需的基础镜像、安装依赖、配置环境变量以及复制本地文件到容器内等操作步骤。通过执行docker build命令基于Dockerfile生成的镜像,可以保证每次部署时,容器内的应用程序环境一致且可重复构建。
2023-12-30 15:13:37
472
编程狂人
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
touch file.txt
- 创建新文件。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
2023-04-28
2023-08-09
2023-06-18
2023-04-14
2023-02-18
2023-04-17
2024-01-11
2023-10-03
2023-09-09
2023-06-13
2023-08-07
2023-03-11
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"