-
Dapr 被设计成一个面向开发者的企业级微服务编程平台,它独立于具体的技术平台,可以运行在“任何地方”。Dapr本身并不提供“基础设施(infrastructure)”,而是利用自身的扩展来适配具体的部署环境。就目前的状态来说,如果希望真正将原生的Dapr应用与生产,只能部署在K8S环境下。虽然Dapr也提供针对Hashicorp Consul的支持,但是目前貌似没有稳定的版本支持。Kubernetes对于很多公司并非“标配”,由于某些原因,它们可以具有一套自研的微服务平台或者弹性云平台,让Dapr与之适配可能更有价值。这两周我们对此作了一些可行性研究,发现这其实不难,记下来我们就同通过一个非常简单的实例来介绍一下大致的解决方案。(拙著《ASP.NET Core 6框架揭秘》热卖中,首印送签名专属书签)。一、NameResolution组件 虽然Dapr提供了一系列的编程模型,比如服务调用、发布订阅和Actor模型等,被广泛应用的应该还是服务调用。我们知道微服务环境下的服务调用需要解决服务注册与发现、负载均衡、弹性伸缩等问题,其实Dapr在这方面什么都没做,正如上面所说,Dapr自身不提供基础设施,它将这些功能交给具体的部署平台(比如K8S)来解决。Dapr中于此相关唯有一个简单得不能再简单的NameResolution组件而已。 从部署的角度来看,Dapr的所有功能都体现在与应用配对的Sidecar上。我们进行服务调用得时候只需要指定服务所在得目标应用的ID(AppID)就可以了。服务请求(HTTP或者gRPC)从应用转到sidecar,后者会将请求“路由”到合适的节点上。如果部署在Kubernetes集群上,如果指定了目标服务的标识和其他相关的元数据(命名空间和集群域名等),服务请求的寻址就不再是一个问题。实际上NameResolution组件体现的针对“名字(Name)”的“解析(Resolution)”解决的就是如将Dapr针对应用的标识AppID转换成基于部署环境的应用标识的问题。从dapr提供的代码来看,它目前注册了如下3种类型的NameResolution组件:mdns:利用mDNS(Multicast DNS)实现服务注册与发现,如果没有显式配置,默认使用的就是此类型。由于mDNS仅仅是在小规模网络中采用广播通信实现的一种DNS,所以根本不适合正式的生成环境。kubernetes:适配Kubernetes的名字解析,目前提供稳定的版本。consul: 适配HashiCorp Consul的名字解析,目前最新为Alpha版本。二、Resolver 一个注册的NameResolution组件旨在提供一个Resolver对象,该对象通过如下的接口来表示。如下面的代码片段所示,Resolver接口提供两个方法,Init方法会在应用启动的时候调用,作为参数的Metadata会携带于当前应用实例相关的元数据(包括应用标识和端口,以及Sidecar的HTTP和gRPC端口等)和针对当前NameResolution组件的配置。对于每一次服务调用,目标应用标识和命名空间等相关信息会被Sidecar封装成一个ResolveRequest 接口,并最为参数调用Resolver对象的ReolveID方法,最终得到一个于当前部署环境相匹配的表示,并利用此标识借助基础设施的利用完整目标服务的调用。package nameresolution type Resolver interface { Init(metadata Metadata) error ResolveID(req ResolveRequest) (string, error) } type Metadata struct { Properties map[string]string `json:"properties"` Configuration interface{} } type ResolveRequest struct { ID string Namespace string Port int Data map[string]string }三、模拟服务注册与负载均衡 假设我们具有一套私有的微服务平台,实现了基本的服务注册、负载均衡,甚至是弹性伸缩的功能,如果希望在这个平台上使用Dapr,我们只需要利用自定义的NameResolution组件提供一个对应的Resolver对象就可以了。我们利用一个ASP.NET Core MVC应用来模拟我们希望适配的微服务平台,如下这个HomeController利用静态字段_applications维护了一组应用和终结点列表(IP+端口)。对于针对某个应用的服务调用,我们通过轮询对应终结点的方式实现了简单的负载均衡。便于后面的叙述,我们将该应用简称为“ServiceRegistry”。public class HomeController: Controller { private static readonly ConcurrentDictionary<string, EndpointCollection> _applications = new(); [HttpPost("/register")] public IActionResult Register([FromBody] RegisterRequest request) { var appId = request.Id; var endpoints = _applications.TryGetValue(appId, out var value) ? value : _applications[appId] = new(); endpoints.TryAdd(request.HostAddress, request.Port); Console.WriteLine($"Register {request.Id} =>{request.HostAddress}:{request.Port}"); return Ok(); } [HttpPost("/resolve")] public IActionResult Resolve([FromBody] ResolveRequest request) { if (_applications.TryGetValue(request.ID, out var endpoints) && endpoints.TryGet(out var endpoint)) { Console.WriteLine($"Resolve app {request.ID} =>{endpoint}"); return Content(endpoint!); } return NotFound(); } } public class EndpointCollection { private readonly List<string> _endpoints = new(); private int _index = 0; private readonly object _lock = new(); public bool TryAdd(string ipAddress, int port) { lock (_lock) { var endpoint = $"{ipAddress}:{port}"; if (_endpoints.Contains(endpoint)) { return false; } _endpoints.Add(endpoint); return true; } } public bool TryGet(out string? endpoint) { lock (_lock) { if (_endpoints.Count == 0) { endpoint = null; return false; } _index++; if (_index >= _endpoints.Count) { _index = 0; } endpoint = _endpoints[_index]; return true; } } }HomeController提供了两个Action方法,Register方法用来注册应用,自定义Resolver的Init方法会调用它。另一个方法Resolve则用来完成根据请求的应用表示得到一个具体的终结点,自定义Resolver的ResolveID方法会调用它。这两个方法的参数类型RegisterRequest和ResolveRequest定义如下,后者和前面给出的同名接口具有一致的定义。两个Action都会在控制台输出相应的文字显示注册的应用信息和解析出来的终结点。public class RegisterRequest { public string Id { get; set; } = default!; public string HostAddress { get; set; } = default!; public int Port { get; set; } } public class ResolveRequest { public string ID { get; set; } = default!; public string? Namespace { get; set; } public int Port { get; } public Dictionary<string, string> Data { get; } = new(); }四、自定义NameResolution组件 由于Dapr并不支持组件的动态注册,所以我们得将其源代码拉下来,修改后进行重新编译。这里涉及到两个git操作,dapr和components-contrib,前者为核心运行时,后者为社区驱动贡献得组件。我们将克隆下来的源代码放在同一个目录下。 我们将自定义的NameResolution组件命名为“svcreg”(服务注册之意),所我们在components-contrib/nameresolution目录(该目录下我们会看到上面提到的几种NameResolution组件的定义)下创建一个同名的目录,并组件代码定义在该目录下的svcreg.go文件中。如下所示的就是该NameResolution组件的完整定义。package svcreg import ( "bytes" "encoding/json" "errors" "fmt" "io/ioutil" "net/http" "strconv" "github.com/dapr/components-contrib/nameresolution" "github.com/dapr/kit/logger" ) type Resolver struct { logger logger.Logger registerEndpoint string resolveEndpoint string } type RegisterRequest struct { Id, HostAddress string Port int64 } func (resolver *Resolver) Init(metadata nameresolution.Metadata) error { var endpoint, appId, hostAddress string var ok bool // Extracts register & resolve endpoint if dic, ok := metadata.Configuration.(map[interface{}]interface{}); ok { endpoint = fmt.Sprintf("%s", dic["endpointAddress"]) resolver.registerEndpoint = fmt.Sprintf("%s/register", endpoint) resolver.resolveEndpoint = fmt.Sprintf("%s/resolve", endpoint) } if endpoint == "" { return errors.New("service registry endpoint is not configured") } // Extracts AppID, HostAddress and Port props := metadata.Properties if appId, ok = props[nameresolution.AppID]; !ok { return errors.New("AppId does not exist in the name resolution metadata") } if hostAddress, ok = props[nameresolution.HostAddress]; !ok { return errors.New("HostAddress does not exist in the name resolution metadata") } p, ok := props[nameresolution.DaprPort] if !ok { return errors.New("DaprPort does not exist in the name resolution metadata") } port, err := strconv.ParseInt(p, 10, 32) if err != nil { return errors.New("DaprPort is invalid") } // Register service (application) var request = RegisterRequest{appId, hostAddress, port} payload, err := json.Marshal(request) if err != nil { return errors.New("fail to marshal register request") } _, err = http.Post(resolver.registerEndpoint, "application/json", bytes.NewBuffer(payload)) if err == nil { resolver.logger.Infof("App '%s (%s:%d)' is successfully registered.", request.Id, request.HostAddress, request.Port) } return err } func (resolver *Resolver) ResolveID(req nameresolution.ResolveRequest) (string, error) { // Invoke resolve service and get resolved target app's endpoint ("{ip}:{port}") payload, err := json.Marshal(req) if err != nil { return "", err } response, err := http.Post(resolver.resolveEndpoint, "application/json", bytes.NewBuffer(payload)) if err != nil { return "", err } defer response.Body.Close() result, err := ioutil.ReadAll(response.Body) if err != nil { return "", err } return string(result), nil } func NewResolver(logger logger.Logger) *Resolver { return &Resolver{ logger: logger, } } 如上面的代码片段所示,我们定义核心的Resolver结构,该接口除了具有一个用来记录日志的logger字段,还有两个额外的字段registerEndpoint和resolveEndpoint,分别代表ServiceRegistry提供的两个API的URL。在为Resolver结构实现的Init方法中,我们从作为参数的元数据中提取出配置,并进一步从配置中提取出ServiceRegistry的地址,并在此基础上添加路由路径“/register”和“/resolve”对Resolver结构的registerEndpoint和resolveEndpoint字段进行初始化。接下来我们从元数据中提取出AppID、IP地址和内部gRPC端口号(外部应用通过此端口调用当前应用的Sidecar),它们被封装成RegisterRequest结构之后被序列化成JSON字符串,并作为输入调用对应的Web API完成对应的服务注册。 在实现的ResolveID中,我们直接将作为参数的ResolveRequest结构序列化成JSON,调用Resolve API。响应主体部分携带的字符串就是为目标应用解析出来的终结点(IP+Port),我们直接将其作为ResolveID的返回值。五、注册自定义NameResolution组件 自定义的NameResolution组件需要显式注册到代表Sidecar的可以执行程序daprd中,入口程序所在的源文件为dapr/cmd/daprd/main.go。我们首先按照如下的方式导入svcreg所在的包”github.com/dapr/components-contrib/nameresolution/svcreg”。// Name resolutions. nr "github.com/dapr/components-contrib/nameresolution" nr_consul "github.com/dapr/components-contrib/nameresolution/consul" nr_kubernetes "github.com/dapr/components-contrib/nameresolution/kubernetes" nr_mdns "github.com/dapr/components-contrib/nameresolution/mdns" nr_svcreg "github.com/dapr/components-contrib/nameresolution/svcreg" 在main函数中,我们找到用来注册NameResolution组件的那部分代码,按照其他NameResolution组件注册那样,依葫芦画瓢完成针对svcreg的注册即可。注册代码中用来提供Resolver的NewResolver函数定义在上述的svcreg.go文件中。runtime.WithNameResolutions( nr_loader.New("svcreg", func() nr.Resolver { return nr_svcreg.NewResolver(logContrib) }), nr_loader.New("mdns", func() nr.Resolver { return nr_mdns.NewResolver(logContrib) }), nr_loader.New("kubernetes", func() nr.Resolver { return nr_kubernetes.NewResolver(logContrib) }), nr_loader.New("consul", func() nr.Resolver { return nr_consul.NewResolver(logContrib) }), ),六、编译部署daprd.exe 到目前为止,所有的编程工作已经完成,接下来我们需要重新编译代表Sidecar的daprd.exe。从上面的代码片段可以看出,dapr的包路径都以“github.com/dapr”为前缀,所以我们需要修改go.mod文件(dapr/go.mod)将依赖路径重定向到本地目录,所以我们按照如下的方式添加了针对“github.com/dapr/components-contrib”的替换规则。replace ( go.opentelemetry.io/otel => go.opentelemetry.io/otel v0.20.0 gopkg.in/couchbaselabs/gocbconnstr.v1 => github.com/couchbaselabs/gocbconnstr v1.0.5 k8s.io/client => github.com/kubernetes-client/go v0.0.0-20190928040339-c757968c4c36 github.com/dapr/components-contrib => ../components-contrib 在将当前目录切换到“dapr/cmd/daprd/”后,以命令行的方式执行“go build”后会在当前目录下生成一个daprd.exe可执行文件。现在我们需要使用这个新的daprd.exe将当前使用使用的替换掉,该文件所在的目录在“%userprofile%.dapr\bin”。七、配置svcreg 我们之间已经说过,Dapr默认使用的是基于mDNS的NameResolution组件(对于的注册名为为“mdns”)。若要使我们自定义的组件“svcreg”生效,需要修改Dapr的配置文件(%userprofile%.dapr\config.yaml)。如下面的代码片段所示,我们不仅将使用的组件名称设置为“svcreg”(在dapr/cmd/daprd/main.go中注册NameResolution组件时提供的名称),还将服务注册API的URL(http://127.0.0.1:3721)放在了配置中(Resolver的Init方法提取的URL就来源于这里)。apiVersion: dapr.io/v1alpha1 kind: Configuration metadata: name: daprConfig spec: nameResolution: component: "svcreg" configuration: endpointAddress: http://127.0.0.1:3721 tracing: samplingRate: "1" zipkin: endpointAddress: http://localhost:9411/api/v2/spans八、测试效果 我们现在编写一个Dapr应用来验证一下自定义的NameResolution组件是否有效。我们采用《ASP.NET Core 6框架揭秘实例演示[03]:Dapr初体验》提供的服务调用的例子。具有如下定义的App2是一个ASP.NET Core应用,它利用路由提供了用来进行加、减、乘、除运算的API。 using Microsoft.AspNetCore.Mvc; using Shared; var app = WebApplication.Create(args); app.MapPost("{method}", Calculate); app.Run("http://localhost:9999"); static IResult Calculate(string method, [FromBody] Input input) { var result = method.ToLower() switch { "add" => input.X + input.Y, "sub" => input.X - input.Y, "mul" => input.X * input.Y, "div" => input.X / input.Y, _ => throw new InvalidOperationException($"Invalid method {method}") }; return Results.Json(new Output { Result = result }); } public class Input { public int X { get; set; } public int Y { get; set; } } public class Output { public int Result { get; set; } public DateTimeOffset Timestamp { get; set; } = DateTimeOffset.Now; }具有如下定义的App1是一个控制台程序,它利用Dapr客户端SDK调用了上诉四个API。 using Dapr.Client; using Shared; HttpClient client = DaprClient.CreateInvokeHttpClient(appId: "app2"); var input = new Input(2, 1); await InvokeAsync("add", "+"); await InvokeAsync("sub", "-"); await InvokeAsync("mul", "*"); await InvokeAsync("div", "/"); async Task InvokeAsync(string method, string @operator) { var response = await client.PostAsync(method, JsonContent.Create(input)); var output = await response.Content.ReadFromJsonAsync<Output>(); Console.WriteLine( $"{input.X} {@operator} {input.Y} = {output.Result} ({output.Timestamp})"); 在启动ServiceRegistry之后,我们启动App2,控制台上会阐述如下的输出。从输出的NameResolution组件名称可以看出,我们自定义的svcreg正在被使用。由于应用启动的时候会调用Resolver的Init方法进行注册,这一点也反映在ServiceRegistry如下所示的输出上。可以看出注册实例的AppID为”app2”,对应的终结点为“10.181.22.4:60840”。然后我们再启动App1,如下所示的输出表明四次服务调用均成功完成。启动的App1的应用实例同样会在ServiceRegistry中注册。而四次服务调用会导致四次针对Resolver的ResolveID方法的调用,这也体现在ServiceRegistry的输出上。链接:https://www.cnblogs.com/artech/p/dapr-custom-name-resolution.html
-
我们不需要提醒你快速网站加载的重要性。要么是 3 秒,要么是用户离开,因此你必须优化网站性能以符合用户的期望。网站性能的优化是一件大事。它涉及多个方面需要照顾,其中许多取决于网站本身、其复杂性和元素。但是,还有一些适用于任何站点的常用优化方法。集成 CDN内容交付网络(又名 CDN)是一个非常棒的工具,可以集成到你的网站中,因为它可以大大加快你的内容交付速度。因为它是一个分布式服务器网络,所以 CDN 会找到离用户最近的服务器并部署它来交付内容。通过这种方式,内容会走得更短,并提供更好的用户体验。许多 CDN 还具有许多其他可提高网站性能的功能:图像优化、缩小 CSS、代码重组。压缩文件每个文件都需要一些时间来加载。问题是,文件越大,加载的时间就越长。结果,该网站以极其缓慢的方式加载并惹恼了用户。解决大体积文件的问题,压缩它们并享受更快的性能!对于文件压缩,建议使用 Gzip 工具,这是最受信任的工具之一。Gzip 声称可以将文件大小减少多达 70%,并显着提高性能。启用 Gzip 的方法有很多种,具体取决于你的站点。 例如,你可以在 .htaccess 文件中启用 Gzip 或简单地使用插件。使用延迟加载每个网站都包含一定数量的媒体文件(即图像、视频、音频文件),每个元素的加载需要相当长的时间。延迟加载设计模式使媒体文件仅在进入用户视点时才加载。这意味着,当用户打开页面时,它不会立即加载所有媒体文件,而只会加载页面顶部的媒体文件。而且,当用户向下滚动时,页面将加载更多文件。这种技术极大地节省了带宽,同时提供了无缝的用户体验。延迟加载还摆脱了不必要的代码执行并减少了内存使用。你还可以将代码分成不同的包,以便不同的页面仅包含代码块。这样,浏览器将只加载用户所在的那些代码。缩小 CSS 和 JavaScript当你的站点下载 JavaScript 或 CSS 文件时,会向服务器发送一个 HTTP 请求。发送的请求越多,性能就越慢。为了解决这个问题,你可以合并和缩小文件以减少 HTTP 请求的数量,从而提高性能。缩小包括消除空格、不必要的代码行或换行符。要执行此过程,请使用 WP Rocket 或 WillPeavy 等可用插件之一。优化数据库数据库优化可能是你网站性能的瓶颈。虽然有很多方面需要关注,但最常见的是:MySQL 查询优化:使用 EverSQL 查询优化器等工具来微调 MySQL 查询并获得有用的建议,索引:该方法允许更快的行选择和排序,内存容量:如果内存不足,会降低性能,因此你可能需要寻找更强大的托管解决方案。请注意,数据库优化也取决于你的站点。 对于某些网站(即电子商务平台),有一些独特的问题需要处理,因此你需要先进行审核,以确定所有需要优化的问题区域。摆脱阻塞的 JavaScript许多网站最常见的问题之一是阻止渲染的 JavaScript 文件。 要解决此问题,你可以执行以下操作:在 HTML 文档中内联外部锁定脚本使用特殊插件(即 W3 Total Cache)使用 async 属性使 JavaScript 文件异步启用缓存每次用户登陆页面时,浏览器都会加载其内容 - 每次出现新查询时都会这样做。 现在,你能想象每天有多少用户访问你的网站以及浏览器必须加载页面内容的次数吗?为了防止站点为返回的用户加载相同的内容并节省一些加载时间,请启用浏览器缓存。 至于新用户,网站仍会从头开始加载内容,因为新用户的缓存是空的。尽管如此,完整的浏览器缓存可以将站点速度从 2.6 毫秒提高到 1(甚至 0.9),因此强烈建议使用它。快速工具:盖茨比Gatsby 是一个静态站点生成器。 该框架使用初步加载:当用户打开主页时,浏览器在后台模式下加载显示链接到主页的站点其他页面所需的数据。使用 Gatsby 构建的网站是一个 React 应用程序,因此它只加载有关页面之间差异的数据,而不是完整的页面。 在页面之间的转换过程中,虚拟 DOM 被更新。 通过这种方式,用户可以享受高速加载和流畅的网站性能。上述性能优化方法是处理网站慢问题的最常用方法。但是,由于每个网站和 Web 应用程序都是独一无二的,因此你需要首先进行性能审核,以准确识别你的网站存在的问题并提出解决问题的正确方法。原文链接:cid:link_0
-
监控最重要的是在故障发生时,能将告警信息发送出来,让正确的人第一时间获悉故障的详情,只有这样才能尽快排除故障。企业微信很多公司都有使用,而且Alertmanager支持将企业微信作为告警通道。最近组里又来了一个需求:当告警发生时,将告警信息通过企业微信发送给开发的相关负责人,方便尽快排除故障。实际使用Alertmanager来完成这项工作,下面介绍具体的实现方法。详细配置告警通道配置监控最重要的是在故障发生时,能将告警信息发送出来,让正确的人第一时间获悉故障的详情,只有这样才能尽快排除故障。企业微信很多公司都有使用,而且Alertmanager支持将企业微信作为告警通道。按照企业微信的官方文档来配置告警通道,如果觉得麻烦,可以在浏览器上搜索“alertmanager 企业微信”关键字,就有很多配置例子展示。我们需要得到下面五个键值对:wechat_api_url: 'https://qyapi.weixin.qq.com/cgi-bin/'wechat_api_corp_id: '12345678'agent_id: 12345678api_secret: 12345678to_tag: 4这五个键值对需要在Alertmanager中配置,后面四个键的值根据实际情况填写。企业微信有三种ID来选择消息的接收对象:用户ID、部门ID和标签ID。因为第三种方式支持同时包含用户和部门,使用起来比较灵活,这里选择第三种方式。点击“标签详情”,可以看到标签ID,在配置Alertmanager时会用到。Blackbox配置这里直接将配置文件贴出。docker-compose.yaml:version: '3.3'services: blackbox_exporter: image: prom/blackbox-exporter:v0.19.0 ports: - "9115:9115" restart: always volumes: - "./config:/config" command: "--config.file=/config/blackbox.yaml"config/blackbox.yaml:modules: http_get: prober: http timeout: 5s http: valid_http_versions: ["HTTP/1.1", "HTTP/2.0"] valid_status_codes: [200] no_follow_redirects: false tls_config: insecure_skip_verify: trueAlertmanager配置这里是关键,因为告警通知的发送控制都由Alertmanager来控制。配置文件如下。docker-compose.yaml:alertmanager: image: bitnami/alertmanager:0 restart: "always" ports: - 9093:9093 container_name: "alertmanager" volumes: - "./config:/etc/alertmanager"config/config.yml:global: resolve_timeout: 5m wechat_api_url: 'https://qyapi.weixin.qq.com/cgi-bin/' wechat_api_corp_id: '1234567'templates: - '/etc/alertmanager/*.tmpl'route: receiver: wechat group_wait: 1s group_interval: 1s repeat_interval: 2s group_by: [adm] routes: - matchers: - adm="search" receiver: searchEngine group_wait: 10s - matchers: - adm="portalweb" receiver: portalWeb group_wait: 10sreceivers:- name: wechat wechat_configs: - to_tag: infra message: '{{ template "wechat.message" . }}' agent_id: 1000002 message_type: markdown api_secret: verylongstring- name: searchEngine wechat_configs: - to_tag: searchdep message: '{{ template "wechat.message" . }}' agent_id: 1000002 message_type: markdown api_secret: verylongstring- name: portalWeb wechat_configs: - to_tag: portalwebdep message: '{{ template "wechat.message" . }}' agent_id: 1000002 message_type: markdown api_secret: verylongstring有几个参数需要介绍下:group_wait:Alertmanager 在接收到一条新的告警(第一次出现的告警)时,将这条告警发送给 receiver 之前需要等待的时间。group_interval:对于一条已经出现过的告警,alertmanager 每隔 group_interval 时间检查一次告警。repeat_interval: 对于一条已经出现过的告警,每隔 repeat_interval 会重新发送给 receiver。有篇文档整理得很好,这里直接列出来。“Alertmanager 在收到一条新的告警之后,会等待 group_wait 时间,对这条新的告警做一些分组、更新、静默的操作。当第一条告警经过 group_wait 时间之后,Alertmanager 会每隔 group_interval 时间检查一次这条告警,判断是否需要对这条告警进行一些操作,当 Alertmanager 经过 n 次 group_interval 的检查后,n*group_interval 恰好大于 repeat_interval 的时候,Alertmanager 才会将这条告警再次发送给对应的 receiver。”文中这三个参数配置的值很小,主要为测试目的,生产环境根据需要配置。还有一点需要注意,Alertmanager子路由(即routes里面)中配置的参数会覆盖根路由(即route里面)中配置的参数,所以按照文件“config/config.yml”中的配置,如果一条告警发送到了“searchEngine”,就不可能再发送给默认的接收者“wechat”,除非子路由没有匹配。告警模板文件:config/wechat.tmpl。{{ define "wechat.message" }}{{- if gt (len .Alerts.Firing) 0 -}}{{- range $index, $alert := .Alerts -}}{{- if eq $index 0 -}}# 报警项: {{ $alert.Labels.alertname }}{{- end }}> `**===告警详情===**` > 告警级别: {{ $alert.Labels.severity }}> 告警详情: <font color="comment">{{ index $alert.Annotations "description" }}{{ $alert.Annotations.message }}</font>> 故障时间: <font color="warning">{{ ($alert.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}</font>> 故障实例: <font color="info">{{ $alert.Labels.instance }}</font>{{- end }}{{- end }}{{- if gt (len .Alerts.Resolved) 0 -}}{{- range $index, $alert := .Alerts -}}{{- if eq $index 0 -}}# 恢复项: {{ $alert.Labels.alertname }}{{- end }}> `===恢复详情===` > 告警级别: {{ $alert.Labels.severity }}> 告警详情: <font color="comment">{{ index $alert.Annotations "description" }}{{ $alert.Annotations.message }}</font>> 故障时间: <font color="warning">{{ ($alert.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}</font>> 恢复时间: <font color="warning">{{ ($alert.EndsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}</font>> 故障实例: <font color="info">{{ $alert.Labels.instance }}</font>{{- end }}{{- end }}{{- end }}其中语句“{{ ($alert.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}”是将时间转换成北京时间,否则默认显示的是UTC时间,不利于故障发生时间的查看。配置完Alertmanager,再看Prometheus的配置。Prometheus配置Prometheus需要增加告警规则文件,所有待监控的metrics都保存在Prometheus中,但它并不知道metrics的值处于什么状态的情况下,自己要发告警给Alertmanager,所以要通过增加告警规则文件告知Prometheus,各个配置文件如下,docker-compose.yaml:version: '3.3'services: prometheus: image: prom/prometheus restart: always ports: - "9090:9090" volumes: - "./config:/config" command: --config.file=/config/prometheus.yamlPrometheus的配置文件,config/prometheus.yaml:# my global configglobal: scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. # scrape_timeout is set to the global default (10s).# Alertmanager configurationalerting: alertmanagers: - static_configs: - targets: - 192.168.52.128:9093# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.rule_files: - /config/alerts.rules # A scrape configuration containing exactly one endpoint to scrape:# Here it's Prometheus itself.scrape_configs: - job_name: 'web-monitor' scrape_interval: 1m metrics_path: /probe params: module: [http_get] static_configs: - targets: - https://www.baidu.com - https://cn.bing.com labels: adm: "search" - targets: - https://www.163.com - https://www.ifeng.com labels: adm: "portalweb" relabel_configs: - source_labels: [__address__] target_label: __param_target - source_labels: [__param_target] target_label: instance - target_label: __address__ replacement: 192.168.52.128:9115 # The blackbox exporter's real hostname:port.Prometheus的告警规则文件,config/alerts.rules:groups: - name: Web监控 rules: - alert: Web API不能访问 expr: probe_success == 0 for: 10s labels: severity: 非常严重 annotations: summary: "{{$labels.instance}}:链接不能访问" description: "{{$labels.instance}}:链接超过10s无法连接"到这里,所有的配置已经完成,看下效果:效果展示在Prometheus上查看probe_success metric的值,看到此时链接“https://www.163.com”访问异常(当然不是真的有问题,可以使用一些手段模拟)。查看Alertmanager Web界面,也收到了Prometheus发送过来的告警信息。企业微信告警信息如下。原文链接:cid:link_0
-
btop命令是一个在Linux系统中查看进程信息的命令,它的概念、起源、发展与现状如下:一、概念btop命令是一个交互式的、实时的、以表格形式展示进程信息的命令行工具。它可以显示当前正在运行的进程列表,包括进程ID、CPU使用率、内存使用率、磁盘I/O等。btop命令还提供了交互式的界面,用户可以通过键盘上的方向键和Page Up/Page Down键来浏览进程列表,以及通过鼠标点击来选择进程进行查看或操作。二、起源btop命令最初是由一个名为Brian K. Jones的开发者创建的,他在使用top命令时发现了一些不满足需求的地方。top命令虽然可以实时查看进程信息,但是它的界面比较简单,无法满足一些用户的需求。因此,Brian K. Jones决定开发一个新的进程查看工具,这就是btop命令的起源。三、发展与现状btop命令自诞生以来,经历了多个版本的发展和改进。随着Linux系统的普及和技术的不断发展,btop命令的功能和性能也不断得到提升。目前,btop命令已经成为一个功能强大、稳定可靠的进程查看工具,被广泛应用于Linux系统中。四、特点与优势相比于其他的进程查看工具,btop命令具有以下特点和优势:交互式界面:btop命令提供了交互式的界面,用户可以通过键盘和鼠标进行操作,更加方便快捷。而其他类似的工具如top、htop等,虽然也提供了实时的进程信息查看功能,但它们的界面相对简单,操作相对较少。实时更新:btop命令可以实时更新进程信息,使得用户可以随时查看最新的进程状态。而其他类似的工具在查看过程中会有一些延迟。自定义显示:btop命令支持自定义显示进程信息,用户可以通过设置选项来选择需要显示的进程信息列和排序方式。而其他类似的工具的显示方式比较固定,无法进行自定义。多进程查看:btop命令支持同时查看多个进程的信息,用户可以通过选择不同的进程进行查看和比较。而其他类似的工具只能查看当前正在运行的进程信息。更好的性能:btop命令在性能方面比其他类似的工具更胜一筹,它可以更快地加载和显示进程信息,而且在处理大量进程信息时也不会出现卡顿的情况。简洁的界面:与其他类似工具相比,btop界面更为简洁,能够显示更多有用的信息。同时,它还支持过滤功能,可以快速查找特定进程。强大的功能:btop不仅提供了基本的进程查看功能,还支持杀死进程、终止进程等操作。此外,它还支持排序功能,可以根据CPU占用率、内存占用率等指标对进程进行排序。可定制性:与其他类似工具相比,btop的可定制性更高。用户可以通过修改配置文件或使用命令行选项来定制界面风格、显示内容等。这使得btop更加灵活和适应不同的使用场景。国际化支持:btop具有良好的国际化支持,可以显示不同语言的进程信息。同时,它还支持多种时区,可以根据用户所在地的时区来显示时间信息。与其他工具集成:btop可以与其他Linux系统工具集成,如与网络监视工具iftop集成,方便用户查看网络流量情况;与系统监控工具htop集成,方便用户查看系统资源使用情况等。这种集成使得btop成为一个功能强大的系统监控工具箱的一部分。五、安装方式红帽系Linux用yum或dnf安装即可。其他Linux发行版安装方式如下。# 下载压缩包wget https://github.com/aristocratos/btop/releases/download/v1.2.13/btop-x86_64-linux-musl.tbz# 下载解压工具yum install bzip2 -y# 解压bunzip2 btop-x86_64-linux-musl.tbztar xf btop-x86_64-linux-musl.tar# 进入解压后的文件夹,进行安装cd btop# 指定安装的目录make install PREFIX=/opt/btop# 运行/opt/btop/bin/btop六、常规操作btop是一个交互式的、实时的、以表格形式展示进程信息的命令行工具,提供了许多常用的操作。以下是一些btop页面中的常用操作:1.键盘操作:使用键盘上的方向键来浏览进程列表。按“r”键,输入刷新间隔,改变屏幕刷新频率。2.筛选进程:使用数字键选择要查看的进程ID(PID)。按“s”键,根据CPU使用率对进程进行排序。按“m”键,根据内存使用率对进程进行排序。按“d”键,列出数据库节点的数据库监视信息。3.查看进程详细信息:鼠标悬停在进程行上,可以查看该进程的详细信息。按“Tab”键,查看绝对值(ABSOLUTE)、平均值(AVERAGE)、差值(DELTA)三个模式中的进程信息。4.终止进程:在进程列表中选择要终止的进程,按“k”键,输入进程ID(PID)并确认终止。5.搜索进程:按“/”键,输入要搜索的进程名称或关键字,按回车键进行搜索。6.设置显示选项:按“o”键,可以设置显示选项,如是否显示线程、内存使用情况等。7.查看系统资源使用情况:按“1”键,可以查看CPU使用率、内存使用率等系统资源使用情况。8.查看数据库监控信息:按“2”键,可以查看数据库监控信息,如数据库节点会话、集合空间等。9.查看系统资源统计信息:按“3”键,可以查看系统资源统计信息,如磁盘I/O、网络流量等。10.查看系统负载信息:按“4”键,可以查看系统负载信息,如系统平均负载、进程状态等。11.查看网络监视信息:按“5”键,可以查看网络监视信息,如网络连接状态、网络流量等。原文链接:cid:link_0
-
介绍: Ngin x是一个高性能的http和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务,特点:占有内存少,并发能力强。作为中间件具有如下功能:1、制作静态页面2、反向代理3、负载均衡4、动静分离5、会话保持 负载均衡的三种方式 负载均衡有三种部署方式:路由模式、桥接模式、服务直接返回模式。路由模式部署灵活,约60%的用户采用这种方式部署;桥接模式不改变现有的网络架构;服务直接返回(DSR)比较适合吞吐量大特别是内容分发的网络应用。约30%的用户采用这种模式。 1、路由模式(推荐) 路由模式的部署方式,服务器的网关必须设置成负载均衡机的LAN口地址,且与WAN口分署不同的逻辑网络。因此所有返回的流量也都经过负载均衡。这种方式对网络的改动小,能均衡任何下行流量。 2、桥接模式 桥接模式配置简单,不改变现有网络。负载均衡的WAN口和LAN口分别连接上行设备和下行服务器。LAN口不需要配置IP(WAN口与LAN口是桥连接),所有的服务器与负载均衡均在同一逻辑网络中。 由于这种安装方式容错性差,网络架构缺乏弹性,对广播风暴及其他生成树协议循环相关联的错误敏感,因此一般不推荐这种安装架构。 3、服务直接返回模式 这种安装方式负载均衡的LAN口不使用,WAN口与服务器在同一个网络中,互联网的客户端访问负载均衡的虚IP(VIP),虚IP对应负载均衡机的WAN口,负载均衡根据策略将流量分发到服务器上,服务器直接响应客户端的请求。因此对于客户端而言,响应他的IP不是负载均衡机的虚IP(VIP),而是服务器自身的IP地址。也就是说返回的流量是不经过负载均衡的。因此这种方式适用大流量高带宽要求的服务。 接下来就用nginx来实操一下反向代理!!!! 1、WEB服务器环境准备 准备5台服务器 2、环境配置 1.克隆HA1/HA2/WEB1/WEB2/WEB3 2.开机启动 - 修改主机名字 - IP地址 - 修改软件源 - yum cache 3.WEB构建完毕-apache HA1主机配置[root@localhost ~]# hostnamectl set-hostname HA1 && bash[root@ha1 ~]# mkdir /etc/yum.repos.d/bak[root@ha1 ~]# mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak/[root@ha1 ~]# wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && yum clean all && yum makecache[root@ha1 html]# systemctl stop firewalld.service && systemctl disable firewalld.serviceHA2主机配置[root@localhost ~]# hostnamectl set-hostname HA2 && bash[root@ha2 ~]# mkdir /etc/yum.repos.d/bak[root@ha2 ~]# mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak/[root@ha2 ~]# wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && yum clean all && yum makecache[root@ha2 html]# systemctl stop firewalld.service && systemctl disable firewalld.serviceweb1[root@localhost ~]# hostnamectl set-hostname web1 && bash[root@web1 ~]# mkdir /etc/yum.repos.d/bak[root@web1 ~]# mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak/[root@web1 ~]# wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && yum clean all && yum makecache[root@web1 ~]# systemctl stop firewalld.service && systemctl disable firewalld.service[root@web1 ~]# yum install -y httpd[root@web1 ~]# echo "web-server1" >> /var/www/html/index.html[root@web1 ~]# systemctl start httpd.service && systemctl enable httpd.service && systemctl status httpd.serviceweb2[root@localhost ~]# hostnamectl set-hostname web2 && bash[root@web2 ~]# mkdir /etc/yum.repos.d/bak[root@web2 ~]# mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak/[root@web2 ~]# wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && yum clean all && yum makecache[root@web2 ~]# systemctl stop firewalld.service && systemctl disable firewalld.service[root@web2 ~]# yum install -y httpd[root@web2 ~]# echo "web-server1" >> /var/www/html/index.html[root@web2 ~]# systemctl start httpd.service && systemctl enable httpd.service && systemctl status httpd.serviceweb3[root@localhost ~]# hostnamectl set-hostname web3 && bash[root@web3 ~]# mkdir /etc/yum.repos.d/bak[root@web3 ~]# mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak/[root@web3 ~]# wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && yum clean all && yum makecache[root@web3 ~]# systemctl stop firewalld.service && systemctl disable firewalld.service[root@web3 ~]# yum install -y httpd[root@web3 ~]# echo "web-server1" >> /var/www/html/index.html[root@web3 ~]# systemctl start httpd.service && systemctl enable httpd.service && systemctl status httpd.service 3、Nginx软件部署(只在两个HA节点上部署) HA1 安装nginx软件 [root@ha1 ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo[root@ha1 ~]# yum install -y nginx nginx-mod-stream[root@ha1 ~]# systemctl daemon-reload && systemctl start nginx && systemctl enable nginx && systemctl status nginx [root@ha1 ~]# pstree -ap | grep -v grep | grep -i nginx |-nginx,10687 | |-nginx,10688 | `-nginx,10689 [root@ha1 ~]# netstat -nltp | grep -i nginx tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 10687/nginx: master tcp6 0 0 :::80 :::* LISTEN 10687/nginx: masterNginx反向代理-负载均衡部署[root@ha1 ~]# cd /etc/nginx/[root@ha1 nginx]# mv nginx.conf nginx.conf.bak修改配置文件[root@ha1 nginx]# vim nginx.conf# For more information on configuration, see:# * Official English Documentation: http://nginx.org/en/docs/# * Official Russian Documentation: http://nginx.org/ru/docs/user nginx;worker_processes auto;error_log /var/log/nginx/error.log;# [alert] 18037#0: 1024 worker_connections are not enoughpid /run/nginx.pid;# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.include /usr/share/nginx/modules/*.conf;events {worker_connections 1024; # 最多可以建这么多工作节点}##### add to config start #####stream {log_format main '$remote_addr $upstream_addr - [$time_local] $status$upstream_bytes_sent';access_log /var/log/nginx/web_cluster.log main;# upstream-load_balance-Cluster 这个是负载均衡,下面就是负载均衡的配置upstream web_cluster {server 192.168.40.101:80; # server1 IP:portserver 192.168.40.102:80; # server2 IP:portserver 192.168.40.103:80; # server3 IP:port}server {listen 80; # nginx proxy port -proxy_pass web_cluster; # 添加这个就是反向代理}}##### add to config end ##### 注意:listen port 端⼝号码 - ⽤户访问访问端⼝ server1 IP:port 端⼝号码 - 后端服务的实际端⼝ 检查Nginx配置⽂件格式 [root@ha1 nginx]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful 重新加载配置⽂件 [root@ha1 nginx]# nginx -s reload HA2 安装nginx软件 [root@ha2 ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo[root@ha2 ~]# yum install -y nginx nginx-mod-stream[root@ha2 ~]# systemctl daemon-reload && systemctl start nginx && systemctl enable nginx && systemctl status nginx [root@ha2 ~]# pstree -ap | grep -v grep | grep -i nginx [root@ha2 ~]# pstree -ap | grep -v grep | grep -i nginx |-nginx,10361 | |-nginx,10362 | `-nginx,10363 [root@ha2 ~]# netstat -nltp | grep -i nginx tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 10361/nginx: master tcp6 0 0 :::80 :::* LISTEN 10361/nginx: master Nginx反向代理-负载均衡部署 [root@ha1 ~]# cd /etc/nginx/ [root@ha1 nginx]# mv nginx.conf nginx.conf.bak 修改配置文件 [root@ha1 nginx]# vim nginx.conf# For more information on configuration, see:# * Official English Documentation: http://nginx.org/en/docs/# * Official Russian Documentation: http://nginx.org/ru/docs/user nginx;worker_processes auto;error_log /var/log/nginx/error.log;# [alert] 18037#0: 1024 worker_connections are not enoughpid /run/nginx.pid;# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.include /usr/share/nginx/modules/*.conf;events {worker_connections 1024; # 最多可以建这么多工作节点}##### add to config start #####stream {log_format main '$remote_addr $upstream_addr - [$time_local] $status$upstream_bytes_sent';access_log /var/log/nginx/web_cluster.log main;# upstream-load_balance-Cluster 这个是负载均衡,下面就是负载均衡的配置upstream web_cluster {server 192.168.40.101:80; # server1 IP:portserver 192.168.40.102:80; # server2 IP:portserver 192.168.40.103:80; # server3 IP:port}server {listen 80; # nginx proxy port -proxy_pass web_cluster; # 添加这个就是反向代理}}检查Nginx配置⽂件格式[root@ha2 nginx]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful重新加载配置⽂件[root@ha2 nginx]# nginx -s reload原文链接:https://blog.51cto.com/u_15397018/6104876
-
作为系统管理员,我每天都面临着需要快速解决的问题,用户和管理人员期望事情能够顺利地进行。在我管理的这样的一个大型环境中,几乎不可能从头到尾了解所有的系统和产品,所以我必须使用创造性的技术来找到问题的根源,并(希望可以)提出解决方案。当你不知道从哪里开始时,这五个工具可以帮助你找到用户的 IT 问题的源头。作为系统管理员,我每天都面临着需要快速解决的问题,用户和管理人员期望事情能够顺利地进行。在我管理的这样的一个大型环境中,几乎不可能从头到尾了解所有的系统和产品,所以我必须使用创造性的技术来找到问题的根源,并(希望可以)提出解决方案。这是我 20 多年来的日常经验!每天上班时,我从不知道会发生什么。因此,我有一些快速而简陋的技巧,当一个问题落在我的身上,而我又不知道从哪里开始时,我一般就会采用这些技巧。但等一下!在你直接打开命令行之前,请花一些时间与你的用户交谈。是的,这可能很乏味,但他们可能会有一些好的信息给你。请记住,用户可能没有你那么多的经验,你需要对他们说的东西进行一些解释。试着清楚地了解正在发生什么和应该发生什么,然后用技术语言自己描述故障。请注意,大多数用户并不阅读他们面前的屏幕上的内容;这很可悲,但却是事实。确保你和用户都阅读了所有的文字,以收集尽可能多的信息。一旦你收集到了这些信息,就打开命令行,使用这五个工具。Telnet让我从一个经典开始。Telnet 是 SSH 的前身,在过去,它在 Unix 系统上用来连接到远程终端,就像 SSH 一样,但它没有加密。Telnet 在诊断网络连接问题方面有一个非常巧妙和宝贵的技巧:你可以 Telnet 到不是专属于它 TCP 端口(23/TCP)。要做到这一点,可以像平时一样使用 Telnet,但在末尾加上 TCP 端口(例如 telnet localhost 80),以连接到一个网络服务器。这可以让你能够检查一个服务器,看看服务是否正在运行,或者防火墙是否阻挡了它。因此,在没有应用程序客户端,甚至没有登录应用程序的情况下,你可以检查 TCP 端口是否有反应。如果你知道怎么做,有时你可以通过在 Telnet 提示符手动输入并获得响应以检查。网络服务器和邮件服务器是你可以这样做的两个例子。Tcpdumptcpdump 工具可以让你检查网络上正在传输的数据。大多数网络协议都相当简单,如果你把 tcpdump 和一个像 Wireshark 这样的工具结合起来,你会得到一个简单而好用的方法来浏览你所捕获的流量。在如下的例子中,我在下面的窗口中检查数据包,在上面的窗口连接到 TCP 3260 端口。这张截图显示了在现实世界中使用 Wireshark 查看 iSCSI 协议的情况;在这种情况下,我能够确定我们的 QNAP 网络附加存储的配置方式有问题。find如果你不知道从哪里开始,find 命令就是最好的工具。在其最简单的形式中,你可以用它来“寻找”文件。例如,如果我想在所有的目录中进行递归搜索,得到一个 conf 文件的列表,我可以输入:find . -name '*.conf'.但是,find 的一个隐藏的宝藏是,你可以用它对它找到的每个项目执行一个命令。例如,如果我想得到每个文件的长列表,我可以输入;find . -name '*.conf' -exec ls -las {}\;一旦你掌握了这种技术,你就可以用各种创造性的方法来寻找、搜索和以特定方式执行程序。strace我是在 Solaris 上认识 strace 这个概念的,在那里它被称为 truss。今天,它仍然像多年前一样有用。strace 允许你在进程实时运行时检查它在做什么。使用它很简单,只要使用命令 ps -ef,找到你感兴趣的进程 ID。用 strace -p <进程 ID> 启动 strace,它会开始打印出一大堆东西,一开始看起来像垃圾信息。但如果你仔细观察,你会看到你认识的文字,如 OPEN 和 CLOSE 这样的词和文件名。如果你想弄清楚一个程序为什么不工作,这可以引导你走向正确的方向。grep把最好的留到最后:grep。这个工具是如此有用和强大,以至于我很难想出一个简洁的方法来描述它。简单地说,它是一个搜索工具,但它的搜索方式使它如此强大。在问题分析中,我通常会用 grep 搜索一堆日志来寻找一些东西。一个叫 zgrep 的配套命令可以对压缩文件做同样的事情。在下面的例子中,我使用 zgrep bancroft /var/log/* 在所有的日志文件中进行 grep,以查看我在系统中的工作情况。我使用 zgrep 是因为该目录中有压缩文件。使用 grep 的另一个好方法是将其他工具的输出通过管道输送到它里面;这样,它就可以作为一种过滤器来使用。在下面的例子中,我列出了 auth 文件,并通过使用 cat auth.log |grep bancroft 来搜索我的登录信息,看看我都做了什么。这也可以写成 grep bancroft auth.log,但我这里用管道(|)来证明这一点。其他需要考虑的工具你可以用这些工具做更多的事情,但我希望这个简单的介绍能给你一个窗口,让你了解如何用它们来解决你遇到的讨厌的问题。另一个值得你注意的工具是 Nmap,我没有包括它,因为它是如此全面,需要一整篇文章(或更多)来解释它。最后,我建议学习一些白帽和黑客技术;在试图找出问题的根源时,它们可能非常有益,因为它们可以帮助你收集对决策至关重要的信息。原文链接:https://www.51cto.com/article/700548.html
-
自动化是DevOps成功的关键因素。它利用专门的软件工具和方法来自动化软件开发和交付过程中的重复性和手动性任务。它旨在减少人为干预,降低错误,并增强团队成员之间的协作和沟通。自动化在DevOps中扮演着重要角色,它提升了DevOps的效能。通过自动化工具和方法,DevOps团队可以实现以下目标:消除手动和重复性任务。简化流程。在整个软件开发生命周期中实现更高的效率。自动化是DevOps成功的关键因素。它利用专门的软件工具和方法来自动化软件开发和交付过程中的重复性和手动性任务。它旨在减少人为干预,降低错误,并增强团队成员之间的协作和沟通。DevOps中的自动化包括规划、编码、构建、测试、发布和监控等软件开发生命周期的各个阶段。通过自动化这些过程,组织可以获得多个好处,如一致性、速度、可伸缩性和改善的协作。下面是自动化在DevOps中带来的好处:一致性:DevOps中的自动化过程是一致且可预测的。与容易出错的手动过程不同,自动化确保任务每次以相同的方式执行。这种一致性提高了可靠性,降低了错误或差异的风险。速度:DevOps的自动化显著加快了软件开发和交付的速度。自动化消除了等待人工干预的需求,使流程能够立即开始。此外,自动化的流程比手动的流程执行速度要快得多。代码集成、测试和部署等任务几乎可以瞬间完成,使组织能够快速高效地发布软件更新和功能。可伸缩性:自动化对于扩展DevOps流程至关重要。随着组织的增长和管理多个应用程序和环境,手动管理变得不切实际和低效。自动化工具通过自动化手动处理耗时且容易出错的任务,实现无缝扩展。通过自动化,组织可以在业务扩展的同时保持相同的速度和质量。改善的协作:自动化促进团队成员之间更好的协作和沟通。通过自动化重复和常规任务,团队成员可以将重心放在更有价值的工作上,如创新和解决问题。自动化工具还提供了可见性和透明度,使团队成员能够轻松跟踪任务进展、识别瓶颈并有效协作。需要自动化的DevOps流程:尽管自动化可以应用于DevOps的各个流程,但优先考虑为组织带来最大价值的流程非常重要。以下是可以在DevOps中自动化的一些关键流程:规划:规划阶段为软件开发奠定了基础。自动化规划流程(如收集需求、创建发布计划和建立安全策略)可以帮助简化开发的初期阶段。可以使用像Jira、GitHub和Asana这样的工具自动化任务跟踪、问题管理和项目规划。编码:编码阶段的自动化涉及使用源代码仓库(如Git和Subversion)管理代码版本并促进开发人员之间的协作。可以使用自动化代码审查工具确保代码质量和符合编码标准。构建:构建阶段的自动化侧重于将代码编译为可执行的构建结果,并运行自动化测试来验证代码的功能。可以使用像GitLab和Jenkins这样的持续集成工具自动化构建过程,并在对代码仓库进行更改时自动触发测试。测试:自动化测试是DevOps自动化的一个关键方面。它涉及运行各种类型的测试(包括单元测试、集成测试和性能测试),以验证软件的功能和质量。可以将Selenium和JUnit等测试框架集成到DevOps流水线中,自动执行测试并生成测试报告。发布和部署:自动化发布和部署过程可以确保高效且无错误的软件发布。可以使用像Ansible和Chef这样的发布自动化工具将软件打包和部署到生产环境中。可以建立自动化的部署流水线来处理整个发布过程,包括配置管理、环境配置和部署后验证。监控和运维:监控和运维方面的自动化侧重于持续监控生产环境中软件的性能和健康状况。像Sumo Logic这样的监控工具提供实时洞察和警报功能,使组织能够主动识别和解决可能出现的任何问题。还可以实施自动化的事故响应和修复工作流程,以减少停机时间并确保快速解决问题。综合DevOps工具链数据的方法:随着组织采用各种工具和技术来实施DevOps,管理和聚合整个工具链中的数据变得至关重要。综合的DevOps工具链数据方法允许组织全面了解其软件开发和交付过程,识别瓶颈并做出数据驱动的决策。像Sumo Logic这样的工具提供了一个集中的平台,与Jira、GitHub、Jenkins等领先的DevOps工具集成。这种集成允许组织实时收集和分析来自不同来源的数据,使其能够监控性能、跟踪关键指标并优化其DevOps工作流程。结论:自动化是DevOps领域的一个重要变革者。通过自动化重复和手动任务,组织可以在软件开发和交付过程中实现更高的效率、速度和可靠性。从规划到监控,自动化可以应用于DevOps流水线的各个阶段,使团队能够有效协作、扩展运营并以加快的速度交付高质量的软件。为了充分发挥DevOps中自动化的威力,组织应采用统一的工具链数据方法,并将安全作为开发过程的一部分。通过正确的工具和方法,组织可以释放DevOps的潜力,并在当今竞争激烈的数字化领域中保持领先地位。拥抱自动化,简化你的DevOps工作流程,体验它对软件开发和交付过程的变革影响。保持敏捷,保持竞争力,拥抱DevOps自动化的力量。原文链接:https://www.51cto.com/article/762209.html
-
在现代软件开发领域,DevOps 不仅仅是一个流行的词汇,更是一种文化、一种哲学和一种方法论。DevOps 的核心理念是通过开发和运维之间的紧密合作,实现快速交付、高质量和持续创新。本文将深入探讨 DevOps 文化的重要性、原则以及如何在团队中实现开发与运维的融合。在现代软件开发领域,DevOps 不仅仅是一个流行的词汇,更是一种文化、一种哲学和一种方法论。DevOps 的核心理念是通过开发和运维之间的紧密合作,实现快速交付、高质量和持续创新。本文将深入探讨 DevOps 文化的重要性、原则以及如何在团队中实现开发与运维的融合。什么是 DevOps?DevOps 是 Development(开发)和 Operations(运维)的合并,是一种促使开发和运维团队紧密合作的文化和实践。它旨在消除传统开发和运维之间的壁垒,加强协作,实现软件交付的持续性和质量。DevOps 的核心原则1. 自动化DevOps 鼓励使用自动化工具来执行常见的任务,包括构建、测试、部署和监控。自动化可以降低人工错误,加快交付速度,并提高一致性。2. 持续集成和持续交付通过持续集成(CI)和持续交付(CD)实践,开发团队可以频繁地将代码集成到共享的代码库中,并自动化地将变更部署到生产环境中,从而快速地交付新功能和修复。3. 跨功能团队协作DevOps 鼓励开发、测试和运维团队之间的紧密协作。不再是各自为战,而是共同合作,分享知识和责任,以实现共同的目标。4. 反馈循环通过实时监控和反馈,DevOps 团队可以快速发现和解决问题。这有助于持续改进,提高系统的稳定性和性能。5. 基于数据的决策DevOps 鼓励使用数据来指导决策。通过收集和分析性能指标和用户反馈,团队可以做出更明智的决策,优化流程。DevOps 文化的重要性1. 加速交付速度DevOps 的自动化和持续集成/持续交付实践能够显著减少开发到生产的交付时间。这有助于及早地将新功能、改进和修复带到用户手中。2. 提高质量通过自动化测试和持续集成,DevOps 可以确保每次代码更改都经过严格的测试。这有助于提高软件的稳定性和可靠性。3. 增强可靠性DevOps 强调持续监控和反馈,使团队能够更早地发现问题并及时解决。这有助于提高系统的可靠性,并减少意外的中断。4. 提升团队协作DevOps 的跨功能团队协作能够消除团队之间的隔阂,促使开发、测试和运维团队共同合作。这有助于创造一个更有创造力和积极性的工作环境。5. 促进创新通过快速交付和持续改进,DevOps 鼓励团队不断尝试新的想法和解决方案。这有助于推动创新和业务增长。实现 DevOps 文化的步骤1. 打破隔阂消除开发和运维之间的隔阂,鼓励紧密合作和信息共享。可以通过共同的工作流程、工具和沟通渠道来实现。2. 自动化流程引入自动化工具来支持构建、测试、部署和监控。自动化能够提高效率,减少手动操作的风险。3. 持续改进实施持续反馈和持续改进的实践,通过监控和数据分析来发现问题,并及时采取措施进行改进。4. 促进学习与培训提供培训和知识共享机会,让团队成员了解 DevOps 的原则和最佳实践,以及如何运用它们来提升团队的能力。5. 文化变革DevOps 并不仅仅是工具和流程,更是一种文化。鼓励团队成员拥抱变革,从而实现开发和运维的真正融合。总结DevOps 文化代表了一种开发和运维融合的理念,通过自动化、持续集成、持续交付以及团队协作,构建出更高效、质量更高的软件交付流程。通过打破传统的开发与运维之间的隔阂,促使团队紧密合作、持续创新和快速交付,DevOps 成为现代软件开发的关键要素之一。在一个竞争激烈、迅速变化的市场环境中,DevOps 提供了一种有效的方法来应对不断变化的需求和挑战。通过自动化流程,快速交付新功能和改进,提高质量和可靠性,团队可以更灵活地适应市场的需求,提升用户体验,赢得客户的信任。然而,实施 DevOps 文化并不是一蹴而就的过程。它需要团队成员的共同努力、领导者的支持,以及不断的学习和改进。逐步地引入自动化、持续集成、持续交付等实践,培养团队协作和持续改进的习惯,可以帮助组织逐步转变为一个具有高效交付能力的 DevOps 文化。在 DevOps 文化的指导下,开发和运维团队不再是独立的个体,而是共同合作的伙伴。通过共享知识、资源和责任,他们共同推动软件的生命周期,不断提升交付流程的效率和质量。在这种协作和创新的环境中,团队可以更好地应对挑战,迎接机遇,实现持续的成功和成长。原文链接 https://www.51cto.com/article/764959.html
-
云原生架构(Cloud-Native Architecture)是一种基于云计算的应用程序架构和开发方法论,旨在充分发挥云计算平台的优势,提高应用程序的可伸缩性、弹性和可靠性。云原生架构(Cloud-Native Architecture)是一种基于云计算的应用程序架构和开发方法论,旨在充分发挥云计算平台的优势,提高应用程序的可伸缩性、弹性和可靠性。它强调将应用程序设计为微服务、采用容器化部署、自动化管理和持续交付,以实现快速迭代、高效部署和可靠运行。云原生架构的关键特点包括:微服务架构:将应用程序拆分为多个独立的、自治的微服务,每个微服务负责特定的业务功能,并可以独立开发、部署和扩展。微服务之间通过轻量级的通信机制进行交互,例如RESTful API或消息队列。2. 容器化部署:使用容器技术(如Docker)将每个微服务及其依赖项打包成独立的可移植单元。容器提供了环境隔离、一致性和可移植性,使得应用程序可以在不同的环境中轻松部署和运行。3. 自动化管理:利用自动化工具和平台来管理应用程序的部署、配置、扩缩容、监控和治理等任务。自动化减少了人为操作的错误和复杂性,提高了开发和运维的效率。4. 弹性和可伸缩性:云原生架构倡导根据需求动态调整应用程序的资源,实现弹性和可伸缩性。通过自动化的资源管理和负载均衡,应用程序可以根据实际负载进行水平扩展或收缩,以满足用户需求并提供良好的性能。5. 持续交付:采用持续集成和持续部署(CI/CD)的工作流程,实现快速、可靠的应用程序交付。开发团队可以频繁地进行代码集成、构建、测试和部署,以快速响应需求变化,并确保软件质量和稳定性。DevOps(Development and Operations)是一种软件开发和运维的文化和实践方法,旨在通过加强开发团队和运维团队之间的协作和沟通,实现快速交付高质量的软件。DevOps强调自动化、持续集成、持续交付和持续部署等实践,以加速软件开发周期、降低风险和提高团队效率。DevOps的关键原则包括:自动化:DevOps倡导通过自动化工具和流程来实现软件开发、测试、部署和运维的自动化。自动化减少了人为错误,提高了效率和一致性。2. 持续集成(Continuous Integration):开发团队频繁地将代码集成到共享存储库中,并通过自动化构建和测试流程进行验证。持续集成确保了代码的质量和稳定性,并提早发现和解决问题。3. 持续交付(Continuous Delivery):持续交付是指在持续集成的基础上,通过自动化的构建、测试和部署流程,将可部署的软件交付给用户。这样可以快速响应用户需求,并降低发布新功能和修复错误的时间。4. 持续部署(Continuous Deployment):持续部署是指将通过持续交付生成的可部署软件自动发布到生产环境中,实现快速的软件发布。持续部署能够快速迭代和交付新功能,提高用户满意度和市场竞争力。5. 跨职能团队合作:DevOps鼓励开发团队和运维团队之间的紧密合作和沟通。通过打破传统的组织和职能隔离,促进团队之间的合作,可以更快地解决问题、提供更好的用户体验。6. 基础设施即代码(Infrastructure as Code):基础设施即代码是指使用代码来定义和管理基础设施资源,例如服务器、网络和存储等。通过基础设施即代码,可以实现基础设施的版本控制、自动化部署和可重复性,提高了部署的速度和可靠性。DevOps的应用可以带来以下优势:● 快速交付:通过自动化和持续集成、持续交付的实践,能够快速交付高质量的软件,缩短上线时间,提高产品迭代速度。● 高质量:通过自动化测试和持续集成,能够更早地发现和解决问题,提高软件的质量和稳定性。● 高效协作:通过跨职能团队合作和沟通,打破组织和职能的隔离,加快问题解决和决策过程,提高团队效率。● 可靠性和稳定性:通过自动化部署和基础设施即代码,减少人为错误和手动操作,提高系统的可靠性和可维护性,降低故障风险,提高系统的稳定性。● 灵活性和可扩展性:通过容器化和弹性伸缩的技术,能够快速调整应用程序的资源,根据实际需求进行扩展或缩减,以适应不断变化的业务需求。● 可追溯性和可恢复性:通过版本控制和日志记录,能够追踪系统的变更和操作历史,便于故障排查和回滚操作,提高系统的可追溯性和可恢复性。● 成本效益:通过自动化和资源优化,能够减少人力成本和资源浪费,提高IT资源的利用率,降低运维和部署的成本。总的来说,DevOps作为一种文化和实践方法,通过强调自动化、协作和持续交付,可以提高软件开发和运维的效率和质量,促进团队之间的协作和沟通,实现快速、稳定和可靠的软件交付,以满足不断变化的业务需求。原文链接:https://www.51cto.com/article/765327.html
-
直播间问答1. 第一个问题是命令行模板有哪些能力呢? ——命令行模板是基于设备命令行格式做了增强,各厂商设备的命令行格式都支持,主要增强四个能力:变量定义、变量约束、if控制语句、for控制语句。2.巡检项定义完成后怎么知道是不是正确的?如果不正确,能知道哪个地方不正确吗? ——针对巡检项的验证场景,我们提供测试功能,帮助用户验证、调测问题。巡检项定义完成后,用户可以点击测试功能,选择一个在线的设备验证。测试结束后结果信息很丰富,会把关键数据渲染成不同颜色,例如匹配有差异的显示为红色,匹配正确的显示为绿色,帮助用户快速确认和找到问题。3.巡检项能校验两个变量之间的关系吗? ——能验证。网络巡检功能是在AOC框架上构建的,也具备了开放可编程的能力,两个变量或者更多变量之间的关系都可以校验。简单来说分为两步,第一步用户需要在AOC中导入一个新的SSP包,SSP包由用户开发,在SSP中提供一个校验函数。 第二步定义巡检项,在变量约束中选择函数类型,系统会关联查询出校验函数名称,通过下拉框选择需要的函数即可。巡检时系统会调用SSP中的函数,把匹配到的变量传入到函数中,根据函数返回值检查是否正确。4.网络巡检任务在执行时命令行时会对设备有影响吗? ——这个对设备没有影响,首先巡检功能下方的命令行会拦截写操作,只能下发读操作,所以是不会修改设备上的任何配置。其次,考虑到频繁的读操作会对设备CPU有一定的压力,我们做了双重保障,第一是短时间之内不允许多次执行重复命令,另一方面相同的命令会在系统缓存一段时间,减少设备的访问次数,所以对设备是没有影响的。5.试用一下网络巡检,到哪里可以体验? ——网络巡检体验环境预计10月上线数通网络开放可编程社区中,请大家关注社区获取最新动态。精彩问题1. 网络巡检对ipv6的业务配置或者连通性测试支持吗? ——如果知道ipv6业务在设备上预期的配置就可以检查。当前网络巡检的主要作用是检视设备的资源状态或网络配置,不支持连通性测试。2. 巡检出问题后,有无响应的整改建议呢? ——整改建议需要在新建巡检项的时候手工录入,如果没有录入则无整改建议。3.这个怎么收费? ——需要购买数字地图基础包License,巡检项可以由客户自定义,如需定制按照专业服务收费。 直播回顾回放地址:https://devzone.huawei.com/cn/enterprise/aoc/videos/index.html?id=166&number=1&from=allVideos3
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签