关于gitlab部署的教程还好,有的看,但到了cicd环节,简直痛苦面具,教程虽多,但断断续续,先不说大部分都是只截取片段,让人云里雾里,不会的看不懂,懂的不需要看,根据步骤跑不起来不说,改了一堆,完全不解释为什么,也分不清是官方要求还是作者自己夹带的私货。痛定思痛,抛弃任何教程,根据报错实时改进,于2023年4月24日完成此篇。
官方文档:
http://docs.gitlab.com/runner/install/docker.html
前提:
已部署gitlab,可参阅 docker部署gitlab CI/CD (一)第一篇:部署gitlab及汉化,内附官方文档链接
开始:
#1.拉取并启动runner
docker run -d --name runner --network=host --restart always -v /srv/gitlab-runner/config:/etc/gitlab-runner -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest
官网没有--network=host这句话,正常情况不需要加。但是我在公司实际测试中,在后面的过程会说请求不到gitlab,加上这句话就好了
注意,挂载目录不能改,不然到最后会报错,找不到docker的守护进程:Preparation failed: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
#2.进入容器内部
docker exec -it 容器id /bin/bash
#3.runner注册
gitlab-runner register
如下图,打开你的项目设置,把URL和token都复制进入
如下图,自己填,tag需要记一下,后续的ci文件里要用到。
镜像由于注册的时候还不懂,随便填了一个,应该填你的项目依赖的环境镜像,mcr.microsoft.com/dotnet/sdk:6.0,随便填也无所谓,yml文件里可以指定
如下图,刷新你的设置页面,会显示已经有了
#4.docker部署的必要环节:修改runner的config文件
默认他会每次拉取hub里的镜像,我想改成使用本地镜像,可以用vi命令,也可以自己用其他方法改
vi /srv/gitlab-runner/config/config.toml
有就改,没有就结尾加上 pull_policy = "if-not-present"
由于runner默认不识别docker命令,所以 volumes加上 "/usr/bin/docker:/usr/bin/docker", "/var/run/docker.sock:/var/run/docker.sock"
官方配置说明:http://docs.gitlab.com/runner/configuration/advanced-configuration.html
改完就生效,不用重启
#5.添加.gitlab-ci.yml文件
在项目根目录创建.gitlab-ci.yml文件,官方各语言项目模板参考:http://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates
以下附上net6项目的简略文件
image: mcr.microsoft.com/dotnet/sdk:6.0 variables: VERSION: "$CI_PIPELINE_ID" stages: - deploy deploy: stage: deploy script: - echo "开始构建镜像:webapi:${VERSION}" - docker build -t webapi:${VERSION} -f ./webapi/Dockerfile . - if [ $(docker ps -aq --filter name=webapi) ]; then echo "暂停旧版容器"; docker stop webapi; echo "删除旧版容器"; docker rm webapi; fi - echo "启动新容器" - docker run -d --name webapi -p 5566:5566 -p 5567:5567 webapi:${VERSION} only: - production tags: - dotnet
解释:
image:mcr.microsoft.com/dotnet/sdk:6.0。依赖net6环境
stages: 定义了多个构建阶段,部署(deploy)阶段。这些阶段将按照定义的顺序依次执行。
$CI_PIPELINE_ID:内置变量,取当前流水线id为版本号
if,如果存在名为webapi的容器,就暂停并删除容器
only: -production 只有production分支的改动才启动deploy阶段
tages: 用于为任务指定标签,让标签为dotnet的runner执行。
#6.把环境拉取到本地
因为前文把runner改为了使用本地镜像,所以需要先把net6sdk拉取到本地
docker pull mcr.microsoft.com/dotnet/sdk:6.0
#7.项目提交改动到gitlab
个人建议先拿前端项目练手,因为后端项目依赖比较复杂,坑比较多,我这还涉及依赖私有nuget包等问题,带来的挫折感,陆陆续续搞了两周才完事。
提交改动,然后打开项目的CI/CD流水线,等一等就会发现已经通过
查看控制台,也可以看到,任务执行成功,build成功,且把我docker里的旧容器删了,重新拿新镜像run了一个新的
结束
关于递归,百度搜索给出了很多答案,无非就是递归是一种思想,其代码量少,但执行效率不高等等,但是讲道理合理地使用也能给我们带来较好的体验!01 【递归思想】递归的本质就是二字:套娃。什么被称之为是递归呢?在函数里面调用自身函数就被称之为是递归。而套娃实际上就是在函数中再次调用同样的函数。以上便是递归的核心理念了,再来看你是否把这个核心理念完整的刻在你的脑海当中去。在编程语言当中我们知道,一个函数是可以调用另一个函数的,那么有个特例如下: 如果函数调用了自己,我们便把函数在运行的时候调用自己的情况叫做是递归。用一个简单的例子来进行说明:那么我们现在假设分析下f(3)当中的结果到底是什么如下:1、当参数x的值等于③的时候,开始进入这个函数。此时这个函数返回值是③+f(②)。注:把x的值给带入到f()函数当中去,尽管返回值的参数是不一样的。也一样带进去即可。那么我们会知道③是一个确定的数值,那么f(②)它是一个不确定的值,又会等于多少?2、当函数的参数为②的时候,它的返回值就是②+f(①)。3、以此类推下去,参数x值为①的时候,函数的返回值就是①+f(0)。在上述的代码中我们可以知道,没有判断
CentOS7默认安装MySQL5.7.23,服务管理发生了变化,从sysvinit(servicemysqlstart)变化为systemd(systemctlstartmysqld.service)最近测试了下MySQL5.7.23的服务管理参数,测试主要涉及Restart,RestartPreventExitStatus,RestartSec,StartLimitInterval四个服务启动参数。【服务启动方式比较】1、CentOS7下MySQL5.7.23默认参数下的服务启动方式MySQLcrash、OOM、kill-9pid三种情况下mysqld进程被终止,都会马上重新启动,间隔100mssystemctlstopmysqld@service不会自动重启2、CentOS6下MySQL5.6.21的服务启动情况MySQLcrash、OOMcrash和oomkill的是mysqld进程,由于存在mysqld_safe的守护进程,会自动重启mysqld对于kill-9的命令,如果只kill-9mysqld进程,mysqld_safe守护进程会重启mysqld,如果mysqld_sa
当问题出现的时候不光要解决还要知道为什么看一下源码:voiddispatchLayout(){ if(mAdapter==null){ Log.e(TAG,"Noadapterattached;skippinglayout"); //leavethestateinSTART return; } if(mLayout==null){ Log.e(TAG,"Nolayoutmanagerattached;skippinglayout"); //leavethestateinSTART return; } .... }复制当Adapter和LayoutManager都没有的时候,就会抛出No…attached;skippinglayout异常众所周知,RecyclerView的出现不光可以代替ListView,也可以代替GridView,所以啊大胸弟,你在用的时候要告诉RecyclerView你要代替的是哪个啊,就是所谓的初始化配置,不配置就会警告报错、不显示数据分割线可以不设置,动画也可以不设置,但是LayoutManager必须设置。 随意示范一下
CSS规范该代码规范运用于我的个人项目种,在制定之时,借鉴了一些大厂和开源组织的代码文档。声明顺序相关的属性声明应当归为一组,并按照下面的顺序排列:Positioning(元素定位)Boxmodel(盒模型)Typographic(字体排版)Visual(颜色视觉)Misc(其它杂项)解释:由于定位(positioning)可以从正常的文档流中移除元素,并且还能覆盖盒模型(boxmodel)相关的样式,因此排在首位。盒模型排在第二位,因为它决定了组件的尺寸和位置。其他属性只是影响组件的内部或者是不影响前两组属性,因此排在后面。示例:.declaration-order{ /*Positioning*/ position:absolute; top:0; right:0; bottom:0; left:0; z-index:100; /*Box-model*/ display:block; float:right; width:100px; height:100px; /*Typography*/ font:normal13px"HelveticaNeue",sa
一、效果图弹跳加载二、实现代码<viewclass="bouncing-loader"> <view></view> <view></view> <view></view> </view>复制@keyframesbouncing-loader{ to{ opacity:0.1; transform:translate3d(0,-20rpx,0); } } .bouncing-loader{ display:flex; justify-content:center; } .bouncing-loader>view{ width:15rpx; height:15rpx; margin:30rpx2rpx; background:red; border-radius:50%; animation:bouncing-loader0.6sinfinitealternate; } .bouncing-loader>view:nth-child(2){ animation-
工作中的一些细节问题:记一次yii2种ajax提交数据时校验出问题,直接跳过addError,报错语不现实‘不存在!’$this->addError('customer_id','不存在!');复制publicfunctionrules() { return[ [['customer_id'],'integer'], [['customer_id'],'required'], ['customer_id','validateCustomerId'], ]; }复制publicfunctionvalidateCustomerId() { $this->addError('customer_id','客户公海不存在!'); //$dataStr=date('Y-m-d',time()); //$startTime=strtotime($dataStr); //
笔者针对测试从业者必须掌握的基本功做了个分层:1、操作系统层在这个层面,至少需要去了解操作系统类型、生产厂商、划时代的版本、典型的应用场景。一般而言,操作系统类型可以分为:unix、linux、windows,咦苹果系统去哪了?苹果系统的核是unix的一个分支。当然了要是细分下去会更多,大家大体了解这三种足够(也可以把macos列为独立的一种、android则自动归为linux系列)从应用的场景又可以分为:桌面版本、服务器版本、移动版本,独立生态的苹果,对于每种所占据的市场地位,也是众所皆知的,如果你不清楚,那你平时就应该多多看看相关科技资讯信息了。从操作系统生产商发行版本来看:windows分两大类:以往桌面版的windows系列和服务器版本的Server系列以及现在桌面、移动合一的windows10。unix:这个就比较多了,例如AIX(工作站、大型计算机常用)、原sun发布的Solaris、惠普发布的HP-UX、A/UX(即苹果系统)linux:这个就更多了,例如centos、fedaro、ubutun、debian、opensuse、redhat、kali等等,国内的就不列,
这里列举的Go语言常见坑都是符合Go语言语法的,可以正常的编译,但是可能是运行结果错误,或者是有资源泄漏的风险。数组是值传递在函数调用参数中,数组是值传递,无法通过修改数组类型的参数返回结果。packagemain import"fmt" funcmain(){ x:=[3]int{1,2,3} func(arr[3]int){ arr[0]=7 fmt.Println(arr) }(x) fmt.Println(x) }复制运行程序,结果如下:[723] [123] Processfinishedwithexitcode0复制在go中最好使用切片,因为切片是引用传递。这个和java是有区别的,java如下:importjava.util.Arrays; publicclassHello{ publicstaticvoidmain(String[]args){ String[]arr={"1","2","3"}; test(arr); System.out.println("maina
事情是这样的,我需要参加一个网络课程,视频讲课的,但是呢,又因为自己白天需要干别的事,就想着怎么把视频录下来晚上回去看,找了WebEx录屏软件,尝试了下,录屏听好,就是不能录电脑内的声音,也就是说,录的是外面人说话的声音,怎么办呢?百度了一下,另外自己尝试了下,终于配置好了。。 第一步:右键小喇叭打开电脑的“录音设备”选项卡 在“录制”选项卡中把“立体声混音”设为默认——确定。 好了电脑这边就设置好了。 第二步:设置WebEx端,在 设置——音频设置向导——在首选录制设备中选择“立体声混音”——下一步完成。 好了,设置完成了,测试一下,可以了。。。哈哈。。 过了几天听网络课,令我郁闷的是。。。耳机内的声音,我周围的声音,全他妈的进去了。。。肿么办。。我想要的是只有耳机内的声音。。。。 幸好,我是一个爱钻研的好孩子。。想了下,肯定在录音设置里可以把外界的声音禁止录进去: 功夫不负有心人,只要把上面第一个:集成式麦克风阵列停用了,只留着下面的那个就ok了。。。哈哈哈
就是将已知的明文密码转换成固定长度的MD5 MD5即Message-DigestAlgorithm5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。 MD5算法具有以下特点: 1、压缩性:任意长度的数据,算出的MD5值长度都是固定的。2、容易计算:从原数据计算出MD5值很容易。3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。4、强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。除了MD5以外,其中比较有名的还有sha-1、RIPEMD以及Haval等。 JAVA中的摘要算法简单示例: package com.zhuifeng.util; &nb
一.寄存器的含义、分类及其逻辑结构 注:本文所有的内容皆是在8086CPU结构下。 寄存器的含义:寄存器是在CPU中进行信息存储区域。它是CPU中的主要部件。是程序猿可以用指令读写的部分。 寄存器的分类:8086CPU总共有14个寄存器,分别是AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。其中AX、BX、CX、DX这四个寄存器通常用来存放一般性的数据,被称为通用寄存器。 寄存器的逻辑结构:8086CPU的所有寄存器都是16位的,以AX为例,寄存器的逻辑结构图如下图所示 但是8086CPU的上一代的寄存器是8位的,所有为了保证兼容,使原来的基于上代CPU编写的程序稍加修改就能运行在8086之上,所有8086的CPU的AX、BX、CX、DX这四个寄存器都可以分为两个独立使用的8位寄存器。 AX可以分为AH和AL; BX可以分为BH和BL; CX可以分为CH和CL; DX可以分为DH和DL; 以AX为例,8086CPU的16位寄存器分为两个8位寄存器的情况如下图所示。 二.几条汇编指令 通过汇编指令控制CPU进行工作,看一下如下图的几条指令。
题目链接: [HNOI2011]卡农 题目要求从$S=\{1,2,3……n\}$中选出$m$个子集满足以下三个条件: 1、不能选空集 2、不能选相同的两个子集 3、每种元素出现次数必须为偶数次 我们考虑递推,设$f[i]$为选$i$个集合满足以上条件的方案数。 考虑容斥: 当确定了前$i-1$个集合后,要满足第三个条件的话,第$i$个集合是唯一确定的,所以总方案数为$A_{2^n-1}^{i-1}$。 去掉第$i$个集合是空集的情况,如果第$i$个集合是空集,那么前$i-1$个集合一定合法,即方案数为$f[i-1]$。 再去掉第$i$个集合与前面某个集合一样的情况,那么显然去掉这两个相同的集合后其他的$i-2$个集合也是合法的,第$i$个集合有$2^n-1-(i-2)$种选择,前面那个与第$i$个集合相同的集合的位置有$i-1$种选择,方案数为$(i-1)*(2^n-1-(i-2))*f[i-2]$。 至此,我们可以得到递推式子$f[i]=A_{2^n-1}^{i-1}-f[i-1]-(i-1)*(2^n-i+1)*f[i-2]$。 #include<set>
记录几个关于模型集成的问题: 1、validateset的留出法(还有k-折交叉验证) 【常见的集成学习方法有Stacking、Bagging和Boosting,同时这些集成学习方法与具体验证集划分联系紧密。】 原来常说的集成学习,跟验证集划分相关,以前常看到集成,但不知道是怎么做,以为是多个模型test结果的处理。 2、dropout也是集成的一种。 以前以为只有在FC层后,因为参数比较多,现在知道还有conv的后面,具体是在激活层后面,pooling层前面。例如 nn.Conv2d(3,64,kernel_size=(3,3),stride=(2,2)), nn.ReLU(), nn.Dropout(0.2),nn.MaxPool2d(2),复制 3、TTA是测试时用的集成方法,虽然代码里有TTA,但是还设里一个False的flag,所以实际是没有用TTA? 但也提醒注意: 集成学习只能在一定程度上提高精度,并需要耗费较大的训练时间,因此建议先使用提高单个模型的精度,再考虑集成学习过程; 具体的集成学习方法需要与验证集划分方法结合,Dropout和TTA在所有场景有可以起作用
获取路径 首先要获取本地应用商店配置文件路径,但是路径在C:\ProgramFiles\文件夹的WindowsApps下,需要权限才能进去,所以需要使用软件魔方来帮助获取 我的网盘下载地址:https://pan.baidu.com/s/1R9MuvlALUI2uhbzmcPCTTg 打开--->设置大师--->右键管理--->添加--->勾选管理员获得所有权 然后来到C:\ProgramFiles\文件夹搜索WindowsApps 找到后右键获取所有权,系统运行一会后,再次点击进入文件夹,找到带有WindowsStore关键字的文件夹 找到appxmanifest.xml配置,此时复制路径 C:\ProgramFiles\WindowsApps\Microsoft.WindowsStore_11712.1001.23.0_x64__8wekyb3d8bbwe\appxmanifest.xml 命令重装 在小娜中搜索WindowsPowershell,右键管理员模式打开,输入 add-appxpackage-register"C:\ProgramFile
你有一套活字字模 tiles,其中每个字模上都刻有一个字母 tiles[i]。返回你可以印出的非空字母序列的数目。 示例1: 输入:"AAB"输出:8解释:可能的序列为"A","B","AA","AB","BA","AAB","ABA","BAA"。示例2: 输入:"AAABBC"输出:188 提示: 1<=tiles.length<=7tiles由大写英文字母组成 来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/letter-tile-possibilities著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 和90.子集II一类题,难点在于如何保证结果不重复。 1publicclassSolution{ 2privatechar[]titles=null; 3privateintcount=0; 4privateboolean[]flag=null; 5privateintlen=-1; 6 7privatevoidhel
参考网上代码,网上的代码是直接输入字符串,修改成输入整数。 #include<iostream> #include<string>#include<stdlib.h>//atoi函数包含的头文件usingnamespacestd;boolcompare(stringa,stringb){ if(a+b>=b+a)//ab>=ba,这个时候不需要交换 { returnfalse; } returntrue;//ab<ba,这个时候需要交换} intmain(){ intn; cin>>n; chararr[20][20]; intarri[20]; stringtemp,str[20]; for(inta=0;a<n;a++) { cin>>arri[a]; _itoa_s(arri[a],arr[a],10); } for(inta=0;a<n;a++) { str[a]=arr[a]; } for(inti=0;i<n-1;i++) { for(intj=n-1;j>i
Description 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板。这是一张有8个大小相同的格子的魔板:12348765我们知道魔板的每一个方格都有一种颜色。这8种颜色用前8个正整数来表示。可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列。对于上图的魔板状态,我们用序列(1,2,3,4,5,6,7,8)来表示。这是基本状态。这里提供三种基本操作,分别用大写字母“A”,“B”,“C”来表示(可以通过这些操作改变魔板的状态):“A”:交换上下两行;“B”:将最右边的一列插入最左边;“C”:魔板中央四格作顺时针旋转。下面是对基本状态进行操作的示范:A:87651234B:41235876C:17248635对于每种可能的状态,这三种基本操作都可以使用。你要编程计算用最少的基本操作完成基本状态到目标状态的转换,输出基本操作序列。【输入格式】输入有多组测试数据只有一行,包括8个整数,用空格分开(这些整数在范围1——8之间),表示目标状态。【输出格式】Line1:包括一个整数,表示最短操作序列的长度。Line2:在字典序
unsafe解引用原始指针 fntest(){ leta=vec![1,2];//声明一个固定容量的不可修改向量a println!("{}",a.capacity());//容量是2 letp=&aas*const_as*mutVec<i32>;//借用a,转换为原始指针。通过*const_可以强转为任意指针,不过解释指针是不安全的,需要unsafe方法或代码块 unsafe{ letmut_a:&mutVec<i32>=&mut*p;//解引用,不安全操作 mut_a.push(3); println!("{:?}",mut_a); } } // 2 [1,2,3] 复制 String fntest(){ letmuta=String::with_capacity(1024); a.push_str("你好"); bincode(&aas*const_as*constu8,24); println!("{:018p}:",a.as_ptr()); bincode(a.as_ptr(),7); println!("{}",a)
前提:表按照uid水平分为2张,其他情况类似推理 需求:通过字段time升序分页,实现select*fromTorderbytimeoffsetXlimitY 1.全局视野法 假设现在要拿到第3页的数据,如下图所述,服务层通过uid取模将数据分布到两个库上去之后,每个数据库都失去了全局视野,数据按照time局部排序之后,不管哪个分库的第3页数据,都不一定是全局排序的第3页数据。 那到底哪些数据才是全局排序的第3页数据呢,暂且分三种情况讨论。 (1)极端情况,两个库的数据完全一样 如果两个库的数据完全相同,只需要每个库offset一半,再取半页,就是最终想要的数据(如上图中粉色部分数据)。 (2)极端情况,结果数据来自一个库 也可能两个库的数据分布及其不均衡,例如db0的所有数据的time都大于db1的所有数据的time,则可能出现:一个库的第3页数据,就是全局排序后的第3页数据(如上图中粉色部分数据)。 (3)一般情况,每个库数据各包含一部分 正常情况下,全局排序的第3页数据,每个库都会包含一部分(如上图中粉色部分数据)。