Gitlab的CICD实际生产环境应用

Gitlab 和 Jenkins 一样,都是很流行的 CI/CD 工具,当然,本站之前推过国人自产的东西 onedev,那个也相当不错,但是用的人毕竟还是少,这回还是用大家都耳熟能详的东西。 本篇就是 Giblab 在生产环境打包发布的一个全流程。 解释一下上图: 首先有两套Git,一套是程序员的Code仓库,另一套是运维的操作代码,里面是一些yaml啊,一些ansible脚本啊 然后流程就是先取出程序员的Code,build出来jar,然后打成镜像推到仓库,然后再取出运维的代码,进行合并,生成k8s的yaml文件,最后推到 kubernetes 中去,这样整个 GitOPS 的流程就完备了 在 gitlab 中非常简单,就是编辑 .gitlab-ci.yaml 文件 image: docker:19.03.12 variables: DOCKER_DRIVER: overlay2 DOCKER_TLS_CERTDIR: "" MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository" TIMEZONE: "Asia/Shanghai" http_proxy: "" https_proxy: "" no_proxy: "" cache: paths: - .m2/repository/ - target/ stages: - build - push - deploy Build: stage: build image: maven:3.5-jdk-8-alpine before_script: - export COMMIT_TIME=$(TZ=CST-8 date +%F-%H-%M) - echo $COMMIT_TIME - echo "COMMIT_TIME=$COMMIT_TIME" >> build.env script: - ./mvnw package artifacts: reports: dotenv: build.env tags: - yunwei Push: stage: push before_script: - docker info || true - echo "$HARBOR_REGISTRY $HARBOR_USERNAME $HARBOR_PASSWORD" - echo "echo Dingfangwen | docker login 172.18.31.28 -u dingfangwen --password-stdin" - echo -n $HARBOR_PASSWORD | docker login $HARBOR_REGISTRY -u $HARBOR_USERNAME --password-stdin script: - docker pull $HARBOR_REGISTRY_IMAGE:latest || true - > docker build --cache-from $HARBOR_REGISTRY_IMAGE:latest --build-arg http_proxy=$http_proxy --build-arg https_proxy=$https_proxy --build-arg no_proxy=$no_proxy --cache-from HARBOR_REGISTRY_IMAGE:latest --tag $HARBOR_REGISTRY_IMAGE:$COMMIT_TIME --tag $HARBOR_REGISTRY_IMAGE:latest . - docker push $HARBOR_REGISTRY_IMAGE:$COMMIT_TIME - docker push $HARBOR_REGISTRY_IMAGE:latest - docker logout $HARBOR_REGISTRY dependencies: - Build tags: - yunwei Deploy: stage: deploy cache: {} image: cnych/kustomize:v1.0 script: - echo $COMMIT_TIME - git config --global user.email "gitlab@git.k8s.local" - git config --global user.name "GitLab CI/CD" - git clone git://172.18.31.50:30000/test-k8s.git - cd test-k8s/prod - kustomize edit set image $HARBOR_REGISTRY_IMAGE:$COMMIT_TIME - cat kustomization.yaml - git commit -am 'PROD image update' - git push origin master dependencies: - Build tags: - yunwei only: - master when: manual 先不着急看这个文件,再普及一下 gitlab 的运行机制,它是通过 gitlab-runner 来执行cd的过程的。配置gitlab runner其实也是一项非常复杂的工作,里面可以配的东西太多了,不是本篇的范畴。我们这里简单来说,runner就是一个Docker容器。更准确的说,就是Docker in Docker。 ...

2022年10月25日 · 3 分钟 · 531 字 · 八戒

sed的进阶用法

sed 和 awk 以及 cut 算是常用工具了,sed的高级用法也需要知道一下 sed 里面有2个空间,一个是pattern space,一个是hold space,默认都是空的 开始处理的时候,就从文件里一行一行读入 pattern space ,进行处理,hold space 只在你需要用到它的时候才会出现: d : 清空pattern space中的内容,立即开始下个循环(意思是跳过默认的输出pattern space内容的阶段???不知理解的对不对) h : 用pattern space中的内容替换hold pattern中的内容 H : 在hold space中的内容后面追加一个换行,把pattern space中的内容追加到hold space中 g : 用hold space中的内容替换pattern space中的内容 G : 在pattern space中的内容后面追加一个换行,把hold space中的内容追加到pattern space中 h, g会替换(可以理解为先清空,再复制), H, G是追加。 hH是放过去,gG是拿过来,小写是替换,大写是追加 分析一下经典的将文件内容反向打印 cat 1.txt 1 2 3 cat 1.txt | sed -n '1!G;h;$p' 3 2 1 ‘1!G;h;$p’ 分析一下,1!G就是说第一行不执行G,从第二行开始执行G;然后h是每行都执行,最后一行的时候执行p input | pattern | hold | command | pattern | hold | command | pattern | hold 1 | 1 | 空行 | | 1 | 空行 | h | 1 | 1 2 | 2 | 1 | G | 21 | 1 | h | 21 | 21 3 | 3 | 21 | G | 321 | 21 | h | 321 | 321 ...

2022年10月24日 · 1 分钟 · 136 字 · 八戒

iptables的基本用法

面试的时候经常会被问到 iptables 的问题,那么下面就运维角度来总结一下基本的用法。 看晕了吧,不要紧,我们关注上面的5个红色,5个链条,然后继续看下面的表,详细解释了上面的流程: 两张图结合起来看,意思就是整个 iptables 可以动手的地方太多了。 我们完全没必要关注那么多的细节,常用的地方就2个: 一、最后的出口nat postrouting iptables -t nat -A POSTROUTING -s 10.11.0.0/16 -j SNAT --to 172.16.8.1 上面是做 openvpn 时常用的,一定记得不要乱用 MASQUERADE,而要指定 特定网段(10.11.0.0/16) 从 特定IP(172.16.8.1) 出去。 二、filter表 filter表是 iptables 缺省不带参数查看的表,用于过滤数据包,这是我们操作的最多的地方 iptables -I INPUT -s 185.207.178.236/32 -p tcp --dport 12530 -j ACCEPT iptables -A INPUT -p tcp --dport 12530 -j DROP 上面就只开放了一个IP 185.207.178.236可以访问本机的12530端口,其余的统统封掉,这是最常用的脚本了。 OK,以上两点是最常用的。其余的端口转发之类的,最好中间用haproxy和nginx进行代理,否则查看 iptables 系统的架构就变得不清晰了。 下面贴上常用的参数: -p tcp/udp/icmp/all 匹配协议,all会匹配所有协议 -s addr[/mask] 匹配源地址 -d addr[/mask] 匹配目标地址 --sport 匹配源端口(可指定连续的端口)如--sport80 --dport 匹配目的端口(可指定连续的端口)如--dport80 -o interface 匹配出口网卡,只适用于FORWARD、POSTROUTING、OUTPUT(例:iptables -A FORWARD -o eth0) -i interface 匹配入口网卡,只适用于PREROUTING、INPUT、FORWARD --icmp-type 匹配icmp类型(使用iptables -p icmp -h可查看可用的icmp类型) --tcp-flags mask comp 匹配TCP标记,mask表示检查范围,comp表示匹配mask中的哪些标记(例:iptables -A FORWARD -p tcp --tcp-flags ALL SYN,ACK -j ACCEPT 表示匹配SYN和ACK标记的数据包) -j DROP/ACCEPT/REJECT/LOG 拒绝/允许/拒绝并发出消息/在/var/log/messages中登记分组匹配的记录 -m mac -mac 绑定MAC地址 -m limit -limit 1/s 1/m 设置时间策略 -s 192.168.1.153或192.168.1.0/24 指定源地址或地址段 -d 192.168.1.153或192.168.1.0/24 指定目标地址或地址段 -s ! 192.168.1.0 指定源地址以外的 基本的2个用法足够满足日常运维的需要了。 ...

2022年10月24日 · 1 分钟 · 125 字 · 八戒

systemd与journalctl的双剑合璧

时代已经进化到 systemd 的年代了,service 应该是彻底没有市场了 systemd 的好处是写程序的时候再也不用 fork 甩脱父进程了,日志直接输出终端即可 对 java 来说也是个好事,所有的日志比如WARN ERROR INFO都可以交给journal来管理,这样要查找日志也非常方便了。 举个例子,我们要把一个java启动的程序做成 systemd 的: vim /etc/systemd/system/circle.service [Unit] After=network.target Wants=network.target [Service] WorkingDirectory=/export/prod/server Type=simple ExecStart=/usr/bin/java -jar -Dspring.config.location=application.properties -Dlog4j2.formatMsgNoLookups=true server.jar Restart=on-failure RestartSec=1s [Install] WantedBy=multi-user.target 然后就可以运行了: systemctl daemon-reload systemctl start circle 注意上面的WorkingDirectory,因为下面java启动指定 application.properties 配置文件的时候没有用绝对路径,那么这里就要指定当前工作目录了。 另外RestartSec=1s也改了,缺省是10ms,太快了 当然这只是第一步,日志是归journal管了,journal还是需要进一步配置的 首先必须要持久化存储到磁盘,否则只会在/run/log/journal内存中存放,重启就没了 #disk-usage查看的是: 内存+/var/log/journal的加起来的总和大小 journalctl --disk-usage 然后我们需要修改配置,让它持久化 vi /etc/systemd/journald.conf Storage=persistent 修改重启 mkdir /var/log/journal systemd-tmpfiles --create --prefix /var/log/journal systemctl restart systemd-journald 最后刷一下,把内存的文件刷到磁盘中 journalctl --flush 还可以设置保存天数: journalctl --vacuum-time=31d 查看是从那一天开始保存的,进目录查看时间戳即可 cd /var/log/journal ls -lha 最后就是一个秘籍了,如果把日志弄出来查看 journalctl -u circle --since "2022-10-19 14:30:00" --until "2022-10-19 15:00:00" 开发人员经常问我要日志,这样就特别方便快捷了,比从log4j的日志目录里拉方便的多。 ...

2022年10月19日 · 1 分钟 · 85 字 · 八戒

awk的用法

awk 是比较强力的工具,跟cut和sed组合起来,会有意想不到的作用 举个简单例子,我们nginx的access.log如下: 110.244.232.88 - - [12/Apr/2022:16:50:06 +0800] help.jjwxc.net "GET /user/article/248 HTTP/1.1" 200 10616 "http://my.jjwxc.net/" 220.244.232.88 - - [12/Apr/2022:16:50:06 +0800] help.jjwxc.net "GET /user/article/248 HTTP/1.1" 200 20616 "http://my.jjwxc.net/" 330.244.232.88 - - [12/Apr/2022:16:50:06 +0800] help.jjwxc.net "GET /user/article/248 HTTP/1.1" 200 30616 "http://my.jjwxc.net/" 410.244.232.88 - - [12/Apr/2022:16:50:06 +0800] help.jjwxc.net "GET /user/article/248 HTTP/1.1" 200 10616 "http://my.jjwxc.net/" 530.244.232.88 - - [12/Apr/2022:16:50:06 +0800] help.jjwxc.net "GET /user/article/248 HTTP/1.1" 200 10616 "http://my.jjwxc.net/" 650.244.232.88 - - [12/Apr/2022:16:50:06 +0800] help.jjwxc.net "GET /user/article/248 HTTP/1.1" 200 50616 "http://my.jjwxc.net/" 760.244.232.88 - - [12/Apr/2022:16:50:06 +0800] help.jjwxc.net "GET /user/article/248 HTTP/1.1" 200 60616 "http://my.jjwxc.net/" 第一个字段是ip,然后倒数第3个是200,表示200 OK,后面的就是传输了多少数据两给客户端 我们要统计一下流量大的前5名是谁。 ...

2022年09月25日 · 1 分钟 · 135 字 · 八戒

Ansible之等待服务状态变成成功

ansible的脚本中我们可能会要启动某项服务并等待,直到服务启动起来,然后再进行下一步 这个非常重要,我们举例来实验一下: - hosts: localhost vars: local__service: ssh tasks: - block: - name: "Stop {{ local__service }} service" systemd: service: "{{ local__service }}" state: stopped - name: "Populate ansible_facts.services variable" ansible.builtin.service_facts: - name: "{{ local__service }} state will be stopped as expected" assert: that: ansible_facts.services[local__service].state == 'stopped' - name: "Start {{ local__service }} service" systemd: service: "{{ local__service }}" state: started - name: "Registered {{ local__service }} state will still be stopped as it was not refreshed" assert: that: ansible_facts.services[local__service].state == 'stopped' - name: "Refresh ansible_facts.services variable" ansible.builtin.service_facts: - name: "{{ local__service }} state will be running as expected" assert: that: ansible_facts.services[local__service].state == 'running' 上面的 playbook 一共有7步: ...

2022年07月29日 · 2 分钟 · 222 字 · 八戒

LVM系统的Restore

在生产系统中使用LVM务必要注意lvm metadata的备份,曾经在京东的时候发生过虚机用了lvm的磁盘系统,然后虚机文件qcow2突然坏掉了,想尽了办法也无法恢复,这给我们拉响了警钟啊,使用lvm的时候务必要备份分区信息,否则坏的时候就欲哭无泪了。 缺省在 /etc/lvm/backup/ 目录下是最新的备份,同样历史版本都在 /etc/lvm/archive/ 目录下。 一、先备份 在开始恢复之前,一定先做个备份 cp -pr /etc/lvm /etc/lvm_bkp 然后去看看archive下的备份信息 ls -l /etc/lvm/archive/vg_storage_00* -rw-------. 1 root root 13722 Oct 28 23:45 /etc/lvm/archive/vg_storage_00419-1760023262.vg -rw-------. 1 root root 14571 Oct 28 23:52 /etc/lvm/archive/vg_storage_00420-94024216.vg ... -rw-------. 1 root root 14749 Nov 23 15:11 /etc/lvm/archive/vg_storage_00676-394223172.vg -rw-------. 1 root root 14733 Nov 23 15:29 /etc/lvm/archive/vg_storage_00677-187019982.vg # 二、最坏的情形恢复pv 警告:这一步只能在VG无法正常运行的时候再运行!!! 先说最坏的情形,LVM的建立路径是 pv —> vg —> lv,假设连 pv(物理卷都没了) 我们选择最近的备份,/etc/lvm/archive/vg_storage_00677-187019982.vg less /etc/lvm/archive/vg_storage_00677-187019982.vg ... physical_volumes { pv0 { id = "BgR0KJ-JClh-T2gS-k6yK-9RGn-B8Ls-LYPQP0" ... 从里面拿到 pv 的 id ,重建 pv pvcreate --uuid "BgR0KJ-JClh-T2gS-k6yK-9RGn-B8Ls-LYPQP0" \ --restorefile /etc/lvm/archive/vg_storage_00677-187019982.vg 三、恢复VG 如果 vg 是正常的,那么就不用做第二步了,直接从备份中恢复即可,先查看一下 ...

2022年07月28日 · 4 分钟 · 646 字 · 八戒

dmesg -T 无时间戳的解决方法

现在版本的 dmesg -T 都是带时间戳的。 但是老的机器,很有可能是没有 -T 这个参数的,直接 dmesg 是这样的: 这个时间戳是天书啊,这还算好的,好歹有。还有更差的,连戳子都没有: 戳子都没有的,需要做以下步骤来加上,机器重启后必须再执行一遍: echo 1 > /sys/module/printk/parameters/printk_time 同时写个脚本,/usr/local/bin/dmesgt.sh #!/bin/bash # Translate dmesg timestamps to human readable format # desired date format date_format="%a %b %d %T %Y" # uptime in seconds uptime=$(cut -d " " -f 1 /proc/uptime) # run only if timestamps are enabled if [ "Y" = "$(cat /sys/module/printk/parameters/time)" ]; then dmesg | sed "s/^\[[ ]*\?\([0-9.]*\)\] \(.*\)/\\1 \\2/" | while read timestamp message; do printf "[%s] %s\n" "$(date --date "now - $uptime seconds + $timestamp seconds" +"${date_format}")" "$message" done else echo "Timestamps are disabled (/sys/module/printk/parameters/time)" fi 这样就可以了,最后我们测试一下: ...

2022年07月25日 · 1 分钟 · 125 字 · 八戒

一次mongodb cpu很high的解决方法

接到同事的通知,说mongodb的cpu很高,下不去,看有什么办法。 看了一下图,cpu都99.4%了,确实很高: 登上机器,首先去看mongod的log,都试如下的查询,都很慢: copy出一条来,备用 2022-07-17T21:30:42.556+0800 I COMMAND [conn196670] command beyou.behaviorAnalysis command: find { find: "behaviorAnalysis", filter: { behavior: { $regex: ".*互动操作.*", $options: "i" }, log: { $regex: ".*\Q观看:《罗马的房子》,\E.*", $options: "i" }, userId: 7345, _class: { $in: [ "com.linkyee.api.domain.po.BehaviorAnalysis" ] } }, $db: "beyou" } planSummary: IXSCAN { _class: 1, behavior: 1, log: 1, userId: 1 } keysExamined:111564 docsExamined:2 cursorExhausted:1 numYields:890 nreturned:2 reslen:571 locks:{ Global: { acquireCount: { r: 891 } }, Database: { acquireCount: { r: 891 } }, Collection: { acquireCount: { r: 891 } } } storage:{} protocol:op_msg 2268ms 发现确实很慢啊,op_msg 居然要2268ms,但是mongodb的数据目录总共才6G多,不客观啊。 ...

2022年07月21日 · 2 分钟 · 248 字 · 八戒

Infrastructure as Code中packer的使用

先普及一下概念,Infrastructure as Code,也就是从代码开始定义整个网络环境、虚机、各种资源等等。 简单说就是在云上用代码来管理一切,无论是vpc、subnetwork、lb、snat、sg、ec2…… 非常符合我的胃口,因为就连架构图,都是用 graphviz 来画的。 那么 Infrastructure as Code (IAC) 可以分为以下五个部分: Ad hoc scripts Configuration Management tools Orchestration tools Provisioning tools Server Templating tools 一、Ad hoc scripts 就是用软件对目的主机进行 point to point 操作,用shell或者ansible都可以。推荐ansible。 在 infosys 面试被一个印度老外问到这问题,因为平时根本不用ansible 的 ad hoc 点对点模式,结果被当场问住。现在才知道这玩意是什么。当然,用 ansible 的话不建议用这个,因为 playbook 是可追溯的。 二、Configuration Management tools 配置管理,这里当然推荐 ansible,每一步的操作都可以有 inventory 和 playbook 可以追溯。 三、Orchestration tools 协同工具,k8s和kvm 四、Provisioning tools 生产工具,当然是terraform,另外,阿里云是支持plumi的,华为腾讯不支持。 五、Server Templating tools 模板工具,这里就是 Packer,其实我们公司现在的模板工具,是八戒从openstack学的,改动Cloud-init的东西。 Packer更标准一下,是进化版的东西,它既可以打kvm镜像,也可以打Docker镜像。 下面我们就看看怎么使用吧,这里先说kvm,因为kvm的比较难,docker的八戒现在还是用Dockerfile,有空了再研究packer: 安装就不多说了,就一个执行文件,下载下来就行,不用装。 Packer的核心是三个部分 builders provisioners post-processors 我们先建立一个空目录,名字随便,就叫 test-image ...

2022年07月17日 · 2 分钟 · 273 字 · 八戒