Spiga

分类为项目实战的文章

Docker Swarm部署2

2025-08-10 10:55:01

摘要:一、安装Harbor 1. Harbor介绍 Harbor是由VMWare在Docker Registry的基础之上进行了二次封装,加进去了很多额外程序,而且提供了一个非常漂亮的web界面。 Project Harbor是一个开源的受信任的云本地注册表项目,用于存储、标记和扫描上下文。 Harbor扩展了开源Docker发行版,增加了用户通常需要的功能,如安全、身份和管理。 Harbor支持高级特性,如用户管理、访问控制、活动监视和实例之间的复制。 2. 功能 多租户内容签名和验证 安全性与漏洞分析 审计日志记录 身份集成和基于角色的访问控制 实例间的镜像复制 可扩展的API和图形UI 国际化(目前为英文和中文) 3. docker compose Harbor在物理机上部署是非常难的,而为了简化Harbor的应用,Harbor官方直接把Harbor做成了在容器中运行的应用,而且这个容器在Harbor中依赖类似redis、mysql、pgsql等很多存储系统,所以它需要编排很多容器协同起来工作,因此VMWare Harbor在部署和使用时,需要借助于Docker的单机编排工具(Docker compose)来实现。 Compose是一个用于定义和运行多容器Docker应用程序的工具。使用Compose,我们可以使用YAML文件来配置应用程序的服务。然后,只需要一个命令,就可以从配置中创建并启动所有服务。 4. 部署 需要提前安装好docker 提前下载好安装包:Release v2.13.2 · goharbor/harbor · GitHub 安装docker-compose DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker} mkdir -p $DOCKER_CONFIG/cli-plugins curl -SL https://github.com/docker/compose/releases/download/v2.39.1/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose docker comp…… 阅读全文

Docker Swarm集群1

2025-08-09 10:45:35

摘要:最近公司有个.net项目需要集群部署,由于不打算使用K8S,计划用docker swarm来搭建整个集群环境。 所以计划用2篇文章,记录一下docker swarm部署的整个过程。 文章使用的环境是本地虚拟机环境,生产环境大同小异。 文中用的到资料下载:docker-swarm.zip 一、安装 Docker 对于 Ubuntu/Debian 系统: # 查看 ip ip a 使用工具测试链接,如putty # 1. 更新软件包索引 sudo apt-get update # 2. 安装依赖包 sudo apt-get install ca-certificates curl gnupg lsb-release # 3. 添加 Docker 官方 GPG 密钥 sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 4. 设置稳定版仓库 echo deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null # 5. 安装 Docker 引擎 sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin # 检查 Docker 版本 docker --version 对于 CentOS/RHEL 系统: # 安装依赖包 sudo yum install -y yum-utils device-mapper-persistent-data lvm2 # 添加 Docker 仓库 sudo yum-config-manager --add-r…… 阅读全文

Dapr 完全离线安装方案

2024-09-01 23:15:28

摘要:Dapr 完全离线安装方案 以下是完整的 Dapr 离线安装指南,无需任何网络连接即可完成全部安装过程: 准备工作(在可联网的机器上) 1. 下载所有必需文件 # 创建离线安装目录 mkdir dapr-offline cd dapr-offline # 下载 Dapr CLI wget https://github.com/dapr/cli/releases/download/v1.15.0/dapr_linux_amd64.tar.gz # 下载 Dapr 运行时 wget https://github.com/dapr/dapr/releases/download/v1.15.5/daprd_linux_amd64.tar.gz # 下载 Dashboard wget https://github.com/dapr/dashboard/releases/download/v0.15.0/dashboard_linux_amd64.tar.gz # 下载默认配置文件 wget https://raw.githubusercontent.com/dapr/dapr/master/daprd-system/config.yaml 2. 下载 Docker 镜像并保存 # 拉取所需镜像 docker pull daprio/dapr:1.15.5 docker pull daprio/placement:1.15.5 docker pull daprio/sentry:1.15.5 docker pull daprio/dashboard:0.15.0 docker pull redis:6-alpine docker pull openzipkin/zipkin:latest # 保存镜像为 tar 文件 docker save -o dapr-1.15.5.tar daprio/dapr:1.15.5 docker save -o placement-1.15.5.tar daprio/placement:1.15.5 docker save -o sentry-1.15.5.tar daprio/sentry:1.15.5 docker save -o dashboard-0.15.0.tar daprio/dashboard:0.15.0 d…… 阅读全文

sqlserver索引优化

2021-11-14 11:12:25

摘要:一、基础概念 1. 聚集索引(Clustered Index) 结构特点 数据存储: 聚集索引决定了表中数据的物理存储顺序。 表中的每一行数据都会按照聚集索引的键值进行排序存储。 叶节点: 聚集索引的叶节点包含实际的数据行。 叶节点的数据行是按照聚集索引的键值连续存储的。 唯一性: 每个表只能有一个聚集索引。 聚集索引的键值必须是唯一的,除非在创建时允许重复键值(通过 ALLOW_ROW_LOCKS 和 ALLOW_PAGE_LOCKS 选项)。 存储效率: 由于数据按照键值连续存储,聚集索引在范围查询和排序操作中非常高效。 如果表中有大量数据,聚集索引的维护成本相对较高,因为插入、删除和更新操作需要重新排列数据。 使用场景 范围查询: 适用于需要频繁进行范围查询(如 BETWEEN、、)的表。 排序和分组: 适用于需要频繁进行排序和分组操作的列。 主键: 通常主键会创建为聚集索引,因为主键需要唯一标识每一行数据,并且主键列通常用于范围查询和排序操作。 数据访问模式: 适用于访问模式以顺序访问数据为主的场景。 2. 非聚集索引(Non-Clustered Index) 结构特点 数据存储: 非聚集索引的键值存储的是指向实际数据行的指针。 表中的数据行可以按照插入顺序或其他顺序存储,但非聚集索引提供了一种快速查找数据的方式。 叶节点: 非聚集索引的叶节点包含指向实际数据行的指针。 叶节点的数据行指针是按照非聚集索引的键值排序的。 唯一性: 每个表可以有多个非聚集索引。 非聚集索引的键值可以是唯一的,也可以不唯一。 存储效率: 非聚集索引的维护成本相对较低,因为插入、删除和更新操作不会重新排列实际数据行。 非聚集索引可以提高特定列的查询性能,但对整个表的数据存储没有影响。 使用场景 等值查询: 适用于需要频繁进行等值查询(如 =、IN)的列。 范围查询: 虽然非聚集索引也可以用于范围查询,但效率可能不如聚集索引,尤其是在范围较大时。 排序和分组: 适用于需要频繁进行排序和分组操作的列。 外键: 外键列通常会创建非聚集索引,以提高外键约束的性能。 数据访问模式: 适用于访问模式以随机访问数据为主的场景。 3. 索引优化规则 避免过多索引: 每个表的…… 阅读全文

数据库调优

2019-11-16 15:35:24

摘要:影响性能因素 数据库结构设计 T-SQL语句 数据量大 事务和隔离级别 硬件资源 IO阻塞 批量删除表数据:大量删除时会记录到日志中,也会造成IO阻塞 优化和注意事项 了解业务 优先考虑第三范式设计,参考设计范式 表关联尽可能少 坚持最小原则 在适当的地方使用约束 用户数据和日志文件隔离存放 T-SQL语句优化 使用字段名,尽量不适用* 条件 从左边开始,先写最小条件锁定最少数据 索引 尽量使用索引字段 索引字段放到左边 不能计算也不要使用函数,否则索引失效 以小表关联大表 SQL语句尽量简单 执行计划 sql官方执行计划文档 执行计划图标和运算符 MSSQLSERVER执行计划详解 - 张龙豪 - 博客园 SQL Server执行计划的理解 - 馨馨妙 - 博客园 点击开启【包括实际的执行计划】 执行计划关键字和图标理解 表扫描: Parameter Table Scan 运算符扫描在当前查询中用作参数的表。 该运算符一般用于存储过程内的 INSERT 查询。 Parameter Table Scan 既是一个逻辑运算符,也是一个物理运算符。 就是扫描查询列整个表全部数据,最耗时性能最低的。 嵌套循环: Nested Loops 运算符执行内部联接、左外部联接、左半部联接和左反半部联接逻辑运算。 嵌套循环联接通常使用索引,针对外部表的每一行在内部表中执行搜索。 查询处理器根据预计的开销来决定是否对外部输入进行排序,以改进内部输入索引上的搜索定位。 将基于所执行的逻辑操作返回所有满足 Argument 列中的(可选)谓词的行。 如果 OPTIMIZED 特性设置为“True”,则表示使用了优化的嵌套循环(或批处理排序) 。 Nested Loops 是一个物理运算符。 有关详细信息,请参阅了解嵌套循环联接。 RID查询 : RID Lookup 是使用提供的行标识符 (RID) 在堆上进行的书签查找。 Argument 列包含用于查找表中的行的书签标签和从中查找行的表的名称。 RID Lookup 通常带有 NESTED LOOP JOIN。 RID Lookup 是一个物理运算符。 有关书签查找的详细信息,请参阅 MSDN SQL Server 博客中的Bookmark Lookup(书签查找)。 哈希匹配: Hash Ma…… 阅读全文

鉴权功能实现

2018-11-16 16:46:20

摘要:需求背景 假设,你正在参与开发一个微服务。微服务通过 HTTP 协议暴露接口给其他系统调用,说直白点就是,其他系统通过 URL 来调用微服务的接口。有一天,你的 leader 找到你说,“为了保证接口调用的安全性,我们希望设计实现一个接口调用鉴权功能,只有经过认证之后的系统才能调用我们的接口,没有认证过的系统调用我们的接口会被拒绝。我希望由你来负责这个任务的开发,争取尽快上线。” 需求分析 1. 第一轮基础分析 对于如何做鉴权这样一个问题,最简单的解决方案就是,通过用户名加密码来做认证。我们给每个允许访问我们服务的调用方,派发一个应用名(或者叫应用 ID、AppID)和一个对应的密码(或者叫秘钥)。调用方每次进行接口请求的时候,都携带自己的 AppID 和密码。微服务在接收到接口调用请求之后,会解析出 AppID 和密码,跟存储在微服务端的 AppID 和密码进行比对。如果一致,说明认证成功,则允许接口调用请求;否则,就拒绝接口调用请求。 2. 第二轮分析优化 不过,这样的验证方式,每次都要明文传输密码。密码很容易被截获,是不安全的。那如果我们借助加密算法(比如 SHA),对密码进行加密之后,再传递到微服务端验证,是不是就可以了呢?实际上,这样也是不安全的,因为加密之后的密码及 AppID,照样可以被未认证系统(或者说黑客)截获,未认证系统可以携带这个加密之后的密码以及对应的 AppID,伪装成已认证系统来访问我们的接口。 这就是典型的“重放攻击” 。 提出问题,然后再解决问题,是一个非常好的迭代优化方法。对于这个问题,我们可以借助 OAuth 的验证思路来解决。调用方将请求接口的 URL 跟 AppID、密码拼接在一起,然后进行加密,生成一个 token。调用方在进行接口请求的的时候,将这个 token 及 AppID,随 URL 一块传递给微服务端。微服务端接收到这些数据之后,根据 AppID 从数据库中取出对应的密码,并通过同样的 token 生成算法,生成另外一个 token。用这个新生成的 token 跟调用方传递过来的 token 对比。如果一致,则允许接口调用请求;否则,就拒绝接口调用请求。 3. 第三轮分析优化 不过,这样的设计仍然存在重放攻击的风险,还是不够安全。每个 URL 拼接上 AppID、密码生成的 token 都是固定的。未认证系统截…… 阅读全文

自定义特性+AOP实现缓存

2018-08-21 22:37:30

摘要:1. 目标 如下代码:我们要实现缓存,但希望让使用者不用关心缓存的具体实现,只需要使用者在要操作缓存的方法上加上特性标注即可。 [Caching(CachingMethod.Remove, GetLinksQuery)] public class CreateLinkCommand {     } [Caching(CachingMethod.Get)] public class GetLinksQuery : IRequestListLinkViewModel {     } 要实现我们的目标,我们把任务分成2部分,首先实现缓存逻辑,然后将缓存基于特性做AOP实现。 2. 缓存实现 首先我们定义一个缓存接口 public interface ICacheProvider {    /// summary    /// 向缓存中添加一个对象。    /// /summary    /// param name=key缓存的键值,该值通常是使用缓存机制的方法的名称。/param    /// param name=valKey缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。/param    /// param name=value需要缓存的对象。/param    void Add(string key, string valKey, object value);    void Put(string key, string valKey, object value);    object Get(string key, string valKey);    void Remove(string key);    bool Exists(string key);    bool Exists(string key, string valKey); } 如上代码,为什么接口中key和valKey2个参数呢?这是因为我们可能会缓存同一个方法不同参数的结果,如在一个获取分页结果的方法中,我们可能会返回不同页的结果。如我们目标中GetLinksQuery方法缓存的值会是一个分页显示结果的字典。key是我们缓存的方法名,valKey这是缓存的字典结果中的字典key,value则是字典的结果。要进一步理解可以查看下面基于内存的默…… 阅读全文

自制原生js工具库——CSS篇

2008-05-08 12:28:02

摘要:源码 /* ******************************************************************* */ /*   CSS FUNCTIONS                                                     */ /* ******************************************************************* */ var CSS = (function() {    var css = {};    // 转换的RGB字符串的形式“的RGB ( 255 , 255 , 255 ) ”到“ #ffffff ”    css.rgb2hex = function(rgbString) {        if (typeof (rgbString) != string || !defined(rgbString.match)) { return null; }        var result = rgbString.match(/^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*/);        if (result == null) { return rgbString; }        var rgb = +result[1] 16 | +result[2] 8 | +result[3];        var hex = ;        var digits = 0123456789abcdef;        while (rgb != 0) {            hex = digits.charAt(rgb 0xf) + hex;            rgb = 4;       }        while (hex.length 6) { hex = '0' + hex; }        return # + hex;   };    // 转换字符样式    css.hyphen2camel = function(property) {        if (!defined(property) || …… 阅读全文

自制原生js工具库——Event篇

2008-05-07 21:28:34

摘要:源码 /* ******************************************************************* */ /*   EVENT FUNCTIONS                                                   */ /* ******************************************************************* */ var Event = (function() {    var ev = {};    //阻止事件冒泡    ev.stopBubble = function(e) {        // 如果传入了事件对象,那么就是非IE浏览器        if (e)        // 因此它支持W3C的stopPropagation            e.stopPropagation();        else        // 否则,我们得使用IE的方式取消事件冒泡            window.event.cancelBubble = true;   };    //防止发生默认浏览器行为    ev.stopDefault = function(e) {        // 防止默认浏览器行为(W3C)        if (e) e.preventDefault();        // IE中防止浏览器行为的捷径        return false;   };    //    // 由 Dean Edwards 所编写的addEvent/removeEvent 2005    // 由Tino Zijdel整理    // http://dean.edwards.name/weblog/2005/10/add-event/    ev.addEvent = function(element, type, handler) {        //为每个事件处理函数赋予一个独立的ID        if (!handler.$$guid) handler.$$guid = ev.addEvent.guid++;        //…… 阅读全文

自制原生js工具库——DOM篇

2008-05-06 23:33:23

摘要:源码 /* ******************************************************************* */ /*   DOM FUNCTIONS                                                     */ /* ******************************************************************* */ var DOM = (function() {    var dom = {};    //查找相关元素的前兄弟元素    dom.prev = function(elem) {        do {            elem = elem.previousSibling;       } while (elem elem.nodeType != 1);        return elem;   };    //查找相关元素的后兄弟元素    dom.next = function(elem) {        do {            elem = elem.nextSibling;       } while (elem elem.nodeType != 1);        return elem;   };    //查找第一个子元素    dom.first = function(elem) {        elem = elem.firstChild;        return elem elem.nodeType != 1 ? nextSibling(elem) : elem;   };    //查找最后一个子元素    dom.last = function(elem) {        elem = elem.lastChild;        return elem elem.nodeType != 1 ? prevSibling(elem) : elem;   };    //查找父元素    dom.parent = function(elem, num) {        num = nu…… 阅读全文