基于Helm安装sentry

前言

最初的需求就是在k8s上安装sentry。之前通过自己梳理sentry工程各组件的关联关系做过一次部署。后面了解到kubernetes的helm官方charts仓库有sentry的部署文件
所以这次想根据helm进行sentry的部署,该篇主要是记录一下自己在使用官网charts部署步骤,以及部署过程中,由于本地部署环境的差异所遇到的一些问题,即解决办法。

先决条件

该chats的安装要满足以下条件:

  • 启用Beta API的Kubernetes 1.4+
  • helm> = v2.3.0以正确的顺序运行“加权”挂钩。
  • 基础架构中的PV供应商支持(启用了持久性存储)

环境说明

  • 主机: 本次安装使用的是一主三从的K8S集群(master0,worker1,worker2,worker3)

该集群基于kubeoperator进行的安装(默认已经安装Helm及Ingress)。

  • 网络: K8S集群所在的宿主机均不能访问外网
  • 存储: 存储选择local-volume的方式。
  • 服务: 集群外部访问内部服务通过nginx-ingress访问,访问端口为80,常规按请求的域名来配置到服务的路由规则。

安装步骤

下载charts

由于K8S所在宿主机无法访问外网,所以我是在通过办公电脑(可访问外网)使用git将charts下载到本上。

git clone https://github.com/kubernetes/charts

然后上传到K8S集群主结点上。

预安装

将charts上传到K8S集群主结点以后,在什么都不改的情况下预安装sentry

helm install --dry-run --debug --namespace=sentry --name sentry  ./sentry

会提示如下信息:


image.png

这是由于sentry的默认安装参数是需要依赖redis和postgresql技术组件的。
我们需要将这些技术组件在安装sentry的时候将这些技术组件一起安装。
而同时安装需要依赖它们的charts

根据提示,我们将charts中的redis和postgres组件生成charts的压缩包

helm package  --namespace=sentry  --name postgres ./postgresql
helm package  --namespace=sentry  --name redis ./redis

然后在sentry目录下创建一个charts目录,将打好的包放在charts目录中,如下图所示:


image.png

完成以上工作,正常情况就可以通过命令生成部署sentry的yaml文件了。

helm install --dry-run --debug --namespace=sentry --name sentry  ./sentry

默认配置大致为通过LoadBanlancer对外提供9000端口访问,
一个sentry-web,
两个sentry-worker
一个sentry-cron
一个postgress数据库
一主多从的redis


image.png

如果生成的配置与你的实际部署有差异,需要自己去修改sentry目录下的values.yaml配置文件进行调整,下面是从官方文档中摘下来的相关配置,可以供你参考。

Parameter Description Default
image.repository Sentry image library/sentry
image.tag Sentry image tag 9.1.2
image.pullPolicy Image pull policy IfNotPresent
image.imagePullSecrets Specify image pull secrets []
sentrySecret Specify SENTRY_SECRET_KEY. If isn't specified it will be generated automatically. nil
web.podAnnotations Web pod annotations {}
web.podLabels Web pod extra labels {}
web.replicacount Amount of web pods to run 1
web.resources.limits Web resource limits {cpu: 500m, memory: 500Mi}
web.resources.requests Web resource requests {cpu: 300m, memory: 300Mi}
web.env Additional web environment variables [{name: GITHUB_APP_ID}, {name: GITHUB_API_SECRET}]
web.nodeSelector Node labels for web pod assignment {}
web.affinity Affinity settings for web pod assignment {}
web.schedulerName Name of an alternate scheduler for web pod nil
web.tolerations Toleration labels for web pod assignment []
web.livenessProbe.failureThreshold The liveness probe failure threshold 5
web.livenessProbe.initialDelaySeconds The liveness probe initial delay seconds 50
web.livenessProbe.periodSeconds The liveness probe period seconds 10
web.livenessProbe.successThreshold The liveness probe success threshold 1
web.livenessProbe.timeoutSeconds The liveness probe timeout seconds 2
web.readinessProbe.failureThreshold The readiness probe failure threshold 10
web.readinessProbe.initialDelaySeconds The readiness probe initial delay seconds 50
web.readinessProbe.periodSeconds The readiness probe period seconds 10
web.readinessProbe.successThreshold The readiness probe success threshold 1
web.readinessProbe.timeoutSeconds The readiness probe timeout seconds 2
web.priorityClassName The priorityClassName on web deployment nil
web.hpa.enabled Boolean to create a HorizontalPodAutoscaler for web deployment false
web.hpa.cputhreshold CPU threshold percent for the web HorizontalPodAutoscaler 60
web.hpa.minpods Min pods for the web HorizontalPodAutoscaler 1
web.hpa.maxpods Max pods for the web HorizontalPodAutoscaler 10
cron.podAnnotations Cron pod annotations {}
cron.podLabels Worker pod extra labels {}
cron.replicacount Amount of cron pods to run 1
cron.resources.limits Cron resource limits {cpu: 200m, memory: 200Mi}
cron.resources.requests Cron resource requests {cpu: 100m, memory: 100Mi}
cron.nodeSelector Node labels for cron pod assignment {}
cron.affinity Affinity settings for cron pod assignment {}
cron.schedulerName Name of an alternate scheduler for cron pod nil
cron.tolerations Toleration labels for cron pod assignment []
cron.priorityClassName The priorityClassName on cron deployment nil
worker.podAnnotations Worker pod annotations {}
worker.podLabels Worker pod extra labels {}
worker.replicacount Amount of worker pods to run 2
worker.resources.limits Worker resource limits {cpu: 300m, memory: 500Mi}
worker.resources.requests Worker resource requests {cpu: 100m, memory: 100Mi}
worker.nodeSelector Node labels for worker pod assignment {}
worker.schedulerName Name of an alternate scheduler for worker nil
worker.affinity Affinity settings for worker pod assignment {}
worker.tolerations Toleration labels for worker pod assignment []
worker.concurrency Celery worker concurrency nil
worker.priorityClassName The priorityClassName on workers deployment nil
worker.hpa.enabled Boolean to create a HorizontalPodAutoscaler for worker deployment false
worker.hpa.cputhreshold CPU threshold percent for the worker HorizontalPodAutoscaler 60
worker.hpa.minpods Min pods for the worker HorizontalPodAutoscaler 1
worker.hpa.maxpods Max pods for the worker HorizontalPodAutoscaler 10
user.create Create the default admin true
user.email Username for default admin admin@sentry.local
user.password Password for default admin Randomly generated
email.from_address Email notifications are from smtp
email.host SMTP host for sending email smtp
email.port SMTP port 25
email.user SMTP user nil
email.password SMTP password nil
email.use_tls SMTP TLS for security false
email.enable_replies Allow email replies false
email.existingSecret SMTP password from an existing secret nil
email.existingSecretKey Key to get from the email.existingSecret secret smtp-password
service.type Kubernetes service type LoadBalancer
service.name Kubernetes service name sentry
service.externalPort Kubernetes external service port 9000
service.internalPort Kubernetes internal service port 9000
service.annotations Service annotations {}
service.nodePort Kubernetes service NodePort port Randomly chosen by Kubernetes
service.loadBalancerSourceRanges Allow list for the load balancer nil
ingress.enabled Enable ingress controller resource false
ingress.annotations Ingress annotations {}
ingress.labels Ingress labels {}
ingress.hostname URL to address your Sentry installation sentry.local
ingress.path path to address your Sentry installation /
ingress.extraPaths Ingress extra paths to prepend to every host configuration. []
ingress.tls Ingress TLS configuration []
postgresql.enabled Deploy postgres server (see below) true
postgresql.postgresqlDatabase Postgres database name sentry
postgresql.postgresqlUsername Postgres username postgres
postgresql.postgresqlHost External postgres host nil
postgresql.postgresqlPassword External/Internal postgres password nil
postgresql.postgresqlPort External postgres port 5432
postgresql.existingSecret Name of existing secret to use for the PostgreSQL password nil
postgresql.existingSecretKey Key to get from the postgresql.existingSecret secret postgresql-password
redis.enabled Deploy redis server (see below) true
redis.host External redis host nil
redis.password External redis password nil
redis.port External redis port 6379
redis.existingSecret Name of existing secret to use for the Redis password nil
redis.existingSecretKey Key to get from the redis.existingSecret secret redis-password
filestore.backend Backend for Sentry Filestore filesystem
filestore.filesystem.path Location to store files for Sentry /var/lib/sentry/files
filestore.filesystem.persistence.enabled Enable Sentry files persistence using PVC true
filestore.filesystem.persistence.existingClaim Provide an existing PersistentVolumeClaim nil
filestore.filesystem.persistence.storageClass PVC Storage Class nil (uses alpha storage class annotation)
filestore.filesystem.persistence.accessMode PVC Access Mode ReadWriteOnce
filestore.filesystem.persistence.size PVC Storage Request 10Gi
filestore.filesystem.persistence.persistentWorkers Mount the PVC to Sentry workers, enabling features such as private source maps false
filestore.gcs.credentialsFile Filename of the service account in secret credentials.json
filestore.gcs.secretName The name of the secret for GCS access nil
filestore.gcs.bucketName The name of the GCS bucket nil
filestore.s3.accessKey S3 access key nil
filestore.s3.secretKey S3 secret key nil
filestore.s3.existingSecret Name of existing secret to use for the S3 keys nil
filestore.s3.bucketName The name of the S3 bucket nil
filestore.s3.endpointUrl The endpoint url of the S3 (using for "MinIO S3 Backend") nil
filestore.s3.signature_version S3 signature version (optional) nil
filestore.s3.region_name S3 region name (optional) nil
filestore.s3.default_acl S3 default acl (optional) nil
config.configYml Sentry config.yml file ``
config.sentryConfPy Sentry sentry.conf.py file ``
metrics.enabled Start an exporter for sentry metrics false
metrics.nodeSelector Node labels for metrics pod assignment {}
metrics.tolerations Toleration labels for metrics pod assignment []
metrics.affinity Affinity settings for metrics pod {}
metrics.schedulerName Name of an alternate scheduler for metrics pod nil
metrics.podLabels Labels for metrics pod nil
metrics.resources Metrics resource requests/limit {}
metrics.service.type Kubernetes service type for metrics service ClusterIP
metrics.service.labels Additional labels for metrics service {}
metrics.image.repository Metrics exporter image repository prom/statsd-exporter
metrics.image.tag Metrics exporter image tag v0.10.5
metrics.image.PullPolicy Metrics exporter image pull policy IfNotPresent
metrics.serviceMonitor.enabled if true, creates a Prometheus Operator ServiceMonitor (also requires metrics.enabled to be true) false
metrics.serviceMonitor.namespace Optional namespace which Prometheus is running in nil
metrics.serviceMonitor.interval How frequently to scrape metrics (use by default, falling back to Prometheus' default) nil
metrics.serviceMonitor.selector Default to kube-prometheus install (CoreOS recommended), but should be set according to Prometheus install { prometheus: kube-prometheus }
hooks.affinity Affinity settings for hooks pods {}
hooks.tolerations Toleration labels for hook pod assignment []
hooks.dbInit.enabled Boolean to enable the dbInit job using a hook true
hooks.dbInit.resources.limits Hook job resource limits {memory: 3200Mi}
hooks.dbInit.resources.requests Hook job resource requests {memory: 3000Mi}
serviceAccount.name name of the ServiceAccount to be used by access-controlled resources autogenerated
serviceAccount.create Configures if a ServiceAccount with this name should be created true
serviceAccount.annotations Configures annotation for the ServiceAccount {}

修改好配置以后,通过下面指令进行预安装

helm install --dry-run --debug --namespace=sentry --name sentry  -f ./sentry/values.yaml  ./sentry

下载依赖镜像

因为K8S集群所在的环境无法访问外网,所以需要自己手动操作:

  • 下载镜像(docker pull )
  • 导出镜像 (docker save > ... )
    或上传镜像 (docker push)
  • 导入镜像(docker load< ...)

默认安装依赖的镜像有:

bitnami/postgresql                                               11.7.0-debian-10-r9   
bitnami/postgres-exporter                                        0.8.0-debian-10-r28   
bitnami/redis                                                    5.0.7-debian-10-r32   
bitnami/redis-exporter                                           1.4.0-debian-10-r3    
sentry                                                           9.1.2
prom/node-exporter                                               v0.18.1 

安装

有了相关镜像以后,就可以进行安装了。

helm install --namespace=sentry --name sentry  --wait ./sentry

Note: We have to use the --wait flag for initial creation because the database creation takes longer than the default 300 seconds
正常情况大概6分钟以后就可以安装成功了。
安装完成以后,就可以通过9000端口访问服务了。

image.png

卸载

卸载应用

如果安装有问题,可以通过如下步骤进行卸载。

helm delete  --purge sentry

卸载PV

 kubectl delete -f pv.yaml 
 kubectl patch pv   local-pv-sentry-postgres  -p '{"metadata":{"finalizers":null}}'
 kubectl patch pv   local-pv-sentry-redis-master  -p '{"metadata":{"finalizers":null}}'
 kubectl patch pv   local-pv-sentry-redis-slave -p '{"metadata":{"finalizers":null}}'
 kubectl patch pv   local-pv-sentry-redis-slave-1 -p '{"metadata":{"finalizers":null}}'

其它

删除以后,看看sentry命令空间还有什么没有删除。

kubectl get all -n sentry

我这里发现job.batch及创建的pod没有删除。
于是通过kubectl delete 把相关东西删除掉,如下所示:

  kubectl delete pod -n sentry sentry-db-init-${VAR}
  kubectl delete job.batch -n sentry sentry-db-init

问题

PostgreSQL

PostgreSQL一般不会有什么问题,如果问题,可以看以下官方摘要。

By default, PostgreSQL is installed as part of the chart. To use an external PostgreSQL server set postgresql.enabled to false and then set postgresql.postgresHost and postgresql.postgresqlPassword. The other options (postgresql.postgresqlDatabase, postgresql.postgresqlUsername and postgresql.postgresqlPort) may also want changing from their default values.
To avoid issues when upgrade this chart, provide postgresql.postgresqlPassword for subsequent upgrades. This is due to an issue in the PostgreSQL chart where password will be overwritten with randomly generated passwords otherwise. See https://github.com/helm/charts/tree/master/stable/postgresql#upgrade for more detail.

Rdis

Redis一般不会有什么问题,如果问题,可以看以下官方摘要。

By default, Redis is installed as part of the chart. To use an external Redis server/cluster set redis.enabled to false and then set redis.host. If your redis cluster uses password define it with redis.password, otherwise just omit it. Check the table above for more configuration options.

Ingress

默认安装配置是使用使用service的loadbalancer。
如果你不是运行在公有云的容器集群环境下的话,是不会成功生成一个EXTERNAL-IP(外网IP)入口来对外提供服务访问的。这种情况下应该是可以修改配置,设置ingress来实现服务的访问。

This chart provides support for Ingress resource. If you have an available Ingress Controller such as Nginx or Traefik you maybe want to set ingress.enabled to true and choose an ingress.hostname for the URL. Then, you should be able to access the installation using that address.

因为我是后面才注意到这个参数,所以我手动的将loadbalance的service删除掉。
手动创建的一个ingress配置,如下图所示:


image.png

这个ingress会路由到服务名称为sentry容器的90端口上,所以也需要确认一下这个service是否存在


image.png

持久化

这个是特别需要注意的,这也是我安装时没注意看文档,安装完成以后才注意到的地方。

This chart is capable of mounting the sentry-data PV in the Sentry worker and cron pods. This feature is disabled by default, but is needed for some advanced features such as private sourcemaps.
You may enable mounting of the sentry-data PV across worker and cron pods by changing filestore.filesystem.persistence.persistentWorkers to true. If you plan on deploying Sentry containers across multiple nodes, you may need to change your PVC's access mode to ReadWriteMany and check that your PV supports mounting across multiple nodes.

当时安装时没有修改这些配置,导致的结果是安装不成功。很多结点处于pending状态。
通过容器状态查询,才发现是PVC没有相关的PV配置。我只好手动自己去创建相关的PV,如下所示:

apiVersion: v1
kind: PersistentVolume
metadata:
  finalizers:
  - kubernetes.io/pv-protection
  name: local-pv-sentry
spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 30Gi
  claimRef:
    apiVersion: v1
    kind: PersistentVolumeClaim
    name: sentry
    namespace: sentry
  local:
    path: /home/local-volume/sentry
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - worker1.mycluster.k8s.com
  persistentVolumeReclaimPolicy: Retain
  storageClassName: storageclass-default
  volumeMode: Filesystem

如果发现PVC与PV绑定状态LOSE的情况,还需要删除PV或PVC重新创建。
这个过程中往往需要将PV或PVC的状态初始化,下面的指令将需要使用到。

 kubectl patch pvc -n ${NAME_SPACE}  ${PVC_NAME} -p '{"metadata":{"finalizers":null}}'
 kubectl patch pv   ${PV_NAME} -p '{"metadata":{"finalizers":null}}'

新建登录用户

如果你和我一样,通过默认安装完成以后,成功访问到登录界面了,却不知道用户是什么的时候。就可以使用如下指令来初始化登录用户。

kubectl exec -it -n sentry $(kubectl get pods  -n sentry  |grep sentry-web |awk '{print $1}') bash
sentry createuser

关于nginx反向代理k8s的ingress的问题

由于部署环境限制,需要通过nginx反向代理访问ingress,再由ingress通过内部域名访问sentry服务。
相关配置如下:

  • nginx配置
    首先在nginx上配置一个location,即某域名下的二级路径为sentry的请求就交由proxy_sentry进行转发。
    其中proxy_set_header Host 值为ingress的HOST名称,如:"sentry.apps.mycluster.k8s.com"。
        location /sentry {
        proxy_pass http://proxy_sentry;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        client_max_body_size 50m;
        }

proxy_sentry为部署有ingress的宿主机IP及端口。

    upstream proxy_sentry{
       server  192.168.0.1:80 weight=1;
       server  192.168.0.2:80 weight=1;
       }
  • ingress配置
    由于前端反向代理需要二级路径/sentry作为路由规则,所以路由到ingress的请求信息将为:

http://域名/sentry/

而sentry的部署是没有/sentry这个相对路径的,那就需要在ingress这个地方将转发过来的请求中的二级路径sentry去掉,通过查询ingress-nginx文档。了解到注解 nginx.ingress.kubernetes.io/rewrite-target 配置可以实现这个功能。
根据文档ingress配置如下所示:(注:我使用的是nginx ingress,如果使用其它类型的ingress实现,该方法应该不能能用。)

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
  name: sentry
  namespace: sentry
spec:
  rules:
  - host: sentry.apps.mycluster.k8s.com
    http:
      paths:
      - backend:
          serviceName: sentry
          servicePort: 9000
        path: /sentry(/|$)(.*)
status:
  loadBalancer: {}

配置完成以后,就可以按照自己创建的sentry项目路径来配置了。
只是配置时需要做一些简单的改动。
如果项目给的DSN为:

http://78fc4fd3aa594897aaddbb1523eaaco6@www.internet-domain.com/1

那么你需要在域名后面加上二级路径,如sentry,修改配置如下:

http://78fc4fd3aa594897aaddbb1523eaaco6@www.internet-domain.com/1

如果域名前有证书,只需要将协议改为https及可,修改配置如下:

https://78fc4fd3aa594897aaddbb1523eaaco6@www.internet-domain.com/1
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,738评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,377评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,774评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,032评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,015评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,239评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,724评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,374评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,508评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,410评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,457评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,132评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,733评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,804评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,022评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,515评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,116评论 2 341