手把手的建站思路和dev-ops方案

手把手的建站思路和dev-ops方案

本文是总结的一个结合前后端项目分离、持续部署、网站反向代理、私有镜像管理、日志收集与过滤展示等内容的dev ops方案,诚然这个方案不会是市面上最成熟的和最好用的,不过在笔者我的实践中,这个方案已经相当可靠和全面,故而想总结分享。

反向代理

首先介绍网站的反向代理是用的traefik,这是一个现代化的反向代理和均衡负载器,针对微服务和云原生设计。我个人使用下来,跟nginx的区别,nginx更适合静态文件部署代理,traefik跟容器构建部署代理更贴近。

这里简单讲一下,trafik怎么使用,在自己服务器自己的目录中,创建一个新的docker-compose.yml文件:

yaml 复制代码
version: '3.8'

  


networks:

dev-ops-network:

external: true

  


services:

traefik:

image: traefik:v2.10

container_name: traefik

restart: always

ports:

- "80:80"

- "443:443"

volumes:

- /var/run/docker.sock:/var/run/docker.sock:ro

- ./letsencrypt:/letsencrypt

networks:

- dev-ops-network

command:

- --api.dashboard=true

- --api.insecure=true

- --providers.docker=true

- --entrypoints.web.address=:80

- --entrypoints.web.http.redirections.entryPoint.to=websecure

- --entrypoints.web.http.redirections.entryPoint.scheme=https

- --entrypoints.websecure.address=:443

- --certificatesresolvers.myresolver.acme.dnschallenge=true

- --certificatesresolvers.myresolver.acme.dnschallenge.provider=myresolver

- [email protected]

- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json

labels:

- "traefik.enable=true"

- "traefik.http.routers.traefik.rule=Host(`traefik.XXX.com`)"

- "traefik.http.routers.traefik.service=api@internal"

- "traefik.http.routers.traefik.entrypoints=websecure"

- "traefik.http.routers.traefik.tls.certresolver=myresolver"

这样配置之后,也顺带完成了SSL证书免费申请,这里配置的traefik.XXX.com,打开就是咱们网站的traefik的dashboard页面。traefik的特点就是针对容器进行自动发现,只要存在同一个容器的网络就会被traefik发现,并且用labels的配置,比如对外DNS host暴露XXX.XXX.com,还可以配置

scss 复制代码
`(Host(`XXX.XXX0.com`) || Host(`XXX.XXX1.com`)) && PathPrefix(`/api`) && !PathPrefix(`/api/auth`)

这样就可以做到,XXX.XXX0.com、XXX.XXX1.com等多个DNS解析,前提是DNS已经在服务商平台解析好了。并且如果是前后端项目希望在同一个网址域名下的,可以用PathPrefix(/api) 来给后端流量进入API,隔离前后端。

然后进入traefik网页,比如就是刚刚配置的traefik.XXX.com,然后进入dashboard的router页面,可以看到这个页面,和对应的信息。

traefik还可以跟cloudflare集成,享受cloudflare的代理模式和对应的SSL证书申请,简单配置如下:

yaml 复制代码
version: '3.8'

  


networks:

dev-ops-network:

external: true

  


services:

traefik:

image: traefik:v2.10

container_name: traefik

restart: always

ports:

- "80:80"

- "443:443"

volumes:

- /var/run/docker.sock:/var/run/docker.sock:ro

- ./letsencrypt:/letsencrypt

networks:

- dev-ops-network

environment:

- [email protected]

- CLOUDFLARE_API_KEY=XXX

command:

- --api.dashboard=true

- --api.insecure=true

- --providers.docker=true

- --entrypoints.web.address=:80

- --entrypoints.web.http.redirections.entryPoint.to=websecure

- --entrypoints.web.http.redirections.entryPoint.scheme=https

- --entrypoints.websecure.address=:443

- --certificatesresolvers.cloudflare.acme.dnschallenge=true

- --certificatesresolvers.cloudflare.acme.dnschallenge.provider=cloudflare

- [email protected]

- --certificatesresolvers.cloudflare.acme.storage=/letsencrypt/acme.json

labels:

- "traefik.enable=true"

- "traefik.http.routers.traefik.rule=Host(`proxy.XXX.com`)"

- "traefik.http.routers.traefik.service=api@internal"

- "traefik.http.routers.traefik.entrypoints=websecure"

- "traefik.http.routers.traefik.tls.certresolver=cloudflare"

这个配置里CLOUDFLARE_EMAIL需要填入自己cloudflare网站的邮件,和对应CLOUDFLARE_API_KEY是cloudflare账号的Global API KEY,然后就可以运行了。值得一提的是,如果用cloudflare来做SSL,可能需要在SSL/TLS 加密配置上改加密模式为完全,不然会有重定向过多的问题。

自托管Git服务、持续集成与镜像仓库

我这里使用自托管服务平台,是开源的gitea,当然用github组织、私人repo、enterprise版等也是可以的,这个自托管方案也不少。

持续集成选择的是jenkins,私有容器镜像仓库选择的是harbor,持续集成的选择大家可能都比较熟悉,选择私有容器镜像仓库,是因为可以做到一些功能,比如harbor就是一个企业级镜像仓库,可以提供镜像安全扫描、身份认证和访问权限管理、API支持和更详细的日志等等。

jenkins、gitea、harbor对应依赖的docker-compose yaml文件以及安装过程就不做多解释了,一般按照官网的引导便可用容器安装使用,对应需要给docker-compose.yaml文件加上:

yaml 复制代码
labels:

- "traefik.enable=true"

- "traefik.http.routers.(对应的service).rule=Host(`XXX.XXXX.com`)"

- "traefik.http.routers.(对应的service).entrypoints=websecure"

- "traefik.http.routers.(对应的service).tls=true"

- "traefik.http.routers.(对应的service).tls.certresolver=cloudflare"

- "traefik.http.services.(对应的service).loadbalancer.server.port=(对应的端口)"

这里harbor有一个很有意思的问题,当harbor自己部署之后,自带的默认的密码无法正常登录。这里有一个文章解决这个问题,这个bug还挺容易遇到的....Harbor正确密码登录不上去

然后进入jenkins的网页之中,下载gitea和Generic Webhook Trigger的插件。然后在dashboard页面,选择new item,然后选择freestyle project,命名item name,然后进入项目的config页面,在Source Code Management上选择git,然后去gitea获得你上传repo的git地址,并且这里要获得gitea用户设置-应用中的access token,填入到jenkins项目配置的Credentials的Gitea Personal Access Token中。Triggers里选择Generic Webhook Trigger,在提示的Is triggered by HTTP requests to http://JENKINS_URL/generic-webhook-trigger/invoke中,把http://JENKINS_URL/generic-webhook-trigger/invoke按照自己网站的url,配置到gitea库的webhook设置里,这里可以在gitea的授权标头里配置一个Bearer <your_token123>,然后在jenkins配置里的Generic Webhook Trigger的Token里填入<your_token123>,这样能直接分别让gitea的hook事件精准触发jenkins配置的job,比如前后端分离的服务,就区分开来trigger。然后在Environment配置USERNAME和PASSWORD,是harbor对应权限的username和password,这里要在jenkins里的Credentials先配置好。然后在Build Steps里,选择execute shell,里面填入:

yaml 复制代码
docker login -u ${USERNAME} -p ${PASSWORD} harbor.XXX.com/XXX/XXX

docker build --platform=linux/amd64 -t harbor.XXX.com/XXX/XXX:alpha .

docker push harbor.XXX.com/XXX/XXX:alpha

以上build steps已经build好新的镜像,并且推送到对应的镜像仓库。

加上下一个build steps,这里需要ssh key需要在jenkins提前配置,这便可以直接trigger网站服务进行拉取新的镜像,这里给的命令是将业务服务器和CICD服务器分开的。如果是一个服务器完成,则不需要前面的ssh命令部分。

yaml 复制代码
ssh -o StrictHostKeyChecking=no [email protected] 'cd /root/deploy/test && docker compose pull test-server && docker compose up -d test-server'

ssh -o StrictHostKeyChecking=no [email protected] 'docker image prune -a -f'

还有一个点是,触发jenkins还有一种方案是配置Jenkinsfile文件,先在jenkins网站下载pipeline插件,在源代码库里就可以通过推送来触发web hook,当然也需要在Gitea(或者自己的Git托管仓库)里配置web hook,然后在Jenkins网站创建项目中,选择Pipeline项目创建,然后选择Pipeline script from SCM,选择Git,填入你的Git repo url,Credentials填入对应的。

Jenkinsfile的配置可以如下:

yaml 复制代码
pipeline {

agent any

  


environment {

DOCKER_REGISTRY = "harbor.XXX.com/XXX/XXX"

IMAGE_TAG = "alpha"

}

  


stages {

stage('Login to Harbor') {

steps {

script {

withCredentials([usernamePassword(credentialsId: 'harbor-credentials', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {

sh 'docker login -u $USERNAME -p $PASSWORD $DOCKER_REGISTRY'

}

}

}

}

  


stage('Build Docker Image') {

steps {

sh 'docker build --platform=linux/amd64 -t ${DOCKER_REGISTRY}:${IMAGE_TAG} .'

}

}

  


stage('Push Docker Image') {

steps {

sh 'docker push ${DOCKER_REGISTRY}:${IMAGE_TAG}'

}

}

  


stage('Pull And Update') {

steps {

sh 'cd /root/deploy/test && docker compose pull test-server && docker compose up -d test-server'

sh 'docker image prune -a -f'

}

}

}

  


post {

always {

sh 'docker logout $DOCKER_REGISTRY'

}

}

}

日志收集

服务器的日志上,使用的是Grafana、Promtail 和 Loki,这三个依赖一同构成了一套完整的日志收集和可视化解决方案,可以类比ELK(Elasticsearch + Logstash + Kibana)。

Grafana是负责日志内容和各种数据源可视化:

Promtail是负责日志收集和推送,Promtail 负责从服务器或容器收集日志,并将日志数据发送到 Loki 进行存储。Loki 是 Grafana 对应的分布式日志聚合系统,专门用于高效存储和查询日志数据。

Grafana、Promtail 和 Loki的docker-compose 的配置如下:

yaml 复制代码
version: '3.8'

  


networks:

dev-ops-network:

external: true

  


services:

loki:

image: grafana/loki:latest

container_name: loki

command: -config.file=/etc/loki/local-config.yaml

networks:

- dev-ops-network

labels:

- "traefik.enable=true"

- "traefik.http.routers.loki.rule=Host(`loki.XXX.com`)"

- "traefik.http.services.loki.loadbalancer.server.port=3100"

- "traefik.http.routers.loki.tls.certresolver=cloudflare"

restart: always

  


promtail:

image: grafana/promtail:latest

container_name: promtail

networks:

- dev-ops-network

volumes:

- (这里是服务器日志存放位置):/var/log

- ./promtail-config.yaml:/etc/promtail/config.yml

command: -config.file=/etc/promtail/config.yml

restart: always

  


grafana:

image: grafana/grafana:latest

container_name: grafana

networks:

- dev-ops-network

environment:

- GF_SECURITY_ADMIN_USER=admin

- GF_SECURITY_ADMIN_PASSWORD=admin

volumes:

- grafana-data:/var/lib/grafana

labels:

- "traefik.enable=true"

- "traefik.http.routers.grafana.rule=Host(`grafana.XXXX.com`)"

- "traefik.http.services.grafana.loadbalancer.server.port=3000"

- "traefik.http.routers.grafana.tls.certresolver=cloudflare"

restart: always

  


volumes:

grafana-data:

在云服务上,在这个docker-compose.yaml文件同一级目录,需要配置loki-config.yamlpromtail-config.yaml,重点是promtail-config.yaml文件,clients的url需要配置为刚刚反向代理的loki的对应路径:

yaml 复制代码
server:

http_listen_port: 9080

grpc_listen_port: 0

  


positions:

filename: /tmp/positions.yaml

  


clients:

- url: https://loki.XXXX.com/loki/api/v1/push

  


scrape_configs:

- job_name: XXX-logs

static_configs:

- targets:

- localhost

labels:

job: XXX-logs

__path__: /var/log/*.log

  

以及刚刚的docker-compose.yaml文件里的:volumes: - (这里是服务器日志存放位置):/var/log 这里的配置很关键,这里就是传到Grafana可视化loki数据源的文件内容。然后就可以去grafana网站登录之后,配置信息源,然后用logs等能力看服务器收集的日志内容了,并且服务器的db数据也可以配置grafana的数据源来进行监控和记录。

总结

这里建站对应的dev-ops的思路就是,Gitea负责Git库和推送代码的web hook触发,Jenkins负责CI/CD的触发接受以及docker build和push,Harbor负责docker镜像私有化仓库存储,并且Jenkins在镜像完成build和push之后,trigger业务服务更新新的镜像。

相关推荐
喝拿铁写前端5 小时前
前端与 AI 结合的 10 个可能路径图谱
前端·人工智能
codingandsleeping5 小时前
浏览器的缓存机制
前端·后端
追逐时光者6 小时前
面试官问:你知道 C# 单例模式有哪几种常用的实现方式?
后端·.net
Asthenia04126 小时前
Numpy:数组生成/modf/sum/输出格式规则
后端
Asthenia04126 小时前
NumPy:数组加法/数组比较/数组重塑/数组切片
后端
Asthenia04126 小时前
Numpy:limspace/arange/数组基本属性分析
后端
Asthenia04126 小时前
Java中线程暂停的分析与JVM和Linux的协作流程
后端
Asthenia04126 小时前
Seata TCC 模式:RootContext与TCC专属的BusinessActionContext与TCC注解详解
后端
自珍JAVA6 小时前
【代码】zip压缩文件密码暴力破解
后端
灵感__idea6 小时前
JavaScript高级程序设计(第5版):扎实的基本功是唯一捷径
前端·javascript·程序员