环境
考虑到业务上对日志收集的需求和费用的问题,就直接将sentry部署到已有的演示环境中。演示环境是腾讯云两台服务器组成的docker swarm,并使用 Portainer 对docker swarm 进行管理,所以我们的部署都是通过 portainer 进行。
两台服务器的 /mnt目录时挂载的同一个NFS目录,这样方便容器进行统一挂载宿主机目录。
Sentry 说明
Sentry的服务端分为web、cron、worker这几个部分,应用(客户端)发生错误后将错误信息上报给web,web处理后放入消息队列(Redis存队列),worker从队列中消费数据进行处理,最终数据将存储在PostgreSQL。
其中web、cron、worker这几个部分使用的是同一个docker 镜像,只是启动时的参数不一样;分别对应 sentry run web、sentry run cron、sentry run worker。
部署
dockerhub上最新的sentry版本为9.1.2,还是3年前更新的,已经不建议自己直接使用 docker 镜像进行部署了,官方推荐基于 bash 脚本安装和升级;但是我还是选择了自己使用doker 镜像部署的方式(这样我就可以直接使用Portainer进行操作);
虚拟网络
创建一个覆盖网络,后续的所以容器都将加入该网络,我们直接使用portainer来创建:
Redis
Redis 用来实现 Sentry中的消息队列, Redis Stack:
version: '3.7'
networks:
yanshi-network:
external: true
services:
redis:
user: root
image: redis:6.0
networks:
- yanshi-network
deploy:
replicas: 1
update_config:
parallelism: 1
delay: 5s
order: stop-first
resources:
limits:
cpus: '0.5'
memory: 1g
ports:
- "6379:6379"
environment:
TZ : 'Asia/Shanghai'
volumes:
- /mnt/redis/data:/data
- /mnt/redis/conf/redis.conf:/etc/redis/redis.conf
entrypoint: docker-entrypoint.sh redis-server /etc/redis/redis.conf
注意:sentry9.1.2 和 redis 高版本存在兼容性问题,redis:6.0是OK的。
PostgreSQL
Sentry 需要PostgreSQL 来存储数据,PostgreSQL Stack:
version: '3.7'
networks:
yanshi-network:
external: true
services:
postgres:
image: postgres:14.0
networks:
- yanshi-network
privileged: true
restart: unless-stopped
volumes:
- /mnt/postgres/data:/var/lib/postgresql/data
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: ******
ports:
- "5432:5432"
Sentry
sentry init
首先我们需要启动一个sentry cli 容器,通过 sentry init 命令生成配置文件 /etc/sentry/config.yml、/etc/sentry/sentry.conf.py, 所以我们需要启动一个sentry 的容器:
version: '3.7'
networks:
yanshi-network:
external: true
services:
cli:
image: sentry:9.1.2
networks:
- yanshi-network
volumes:
- /mnt/sentry/conf:/etc/sentry/
stdin_open: true # -i interactive
tty: true # -t tty
privileged: true
entrypoint: ["sh"] # 执行 sh
然后进入容器执行 sentry init 命令,然后就会在宿主机 /mnt/sentry/conf 目录下会生成两个配置文件:
sentry upgrade
上面我们生成配置文件后,我们就需要对配置文件进行修改;
/etc/sentry/config.yml
# 邮箱配置
mail.host: 'smtp.qq.com'
mail.port: 587
mail.username: xxxx@foxmail.com'
mail.password: 'xxxxxx'
mail.use-tls: true
mail.from: 'xxxx@foxmail.com'
# redis 配置
redis.clusters:
default:
hosts:
0:
host: redis
port: 6379
db: 0
password: xxxxxx
/etc/sentry/sentry.conf.py
# 数据库配置
DATABASES = {
'default': {
'ENGINE': 'sentry.db.postgres',
'NAME': 'sentry',
'USER': 'xx',
'PASSWORD': 'xxxxxx',
'HOST': 'postgres',
'PORT': '',
'AUTOCOMMIT': True,
'ATOMIC_REQUESTS': False,
}
}
# Redis 配置
BROKER_URL = 'redis://:xxxx@redis:6379/0'
在 PostgreSql 中创建对应的数据库,我这里配置的数据库名为 sentry;
然后有到上一步(sentry init)的容器中执行 sentry upgrade, 这一步操作 sentry库中就会自动创建好系统需要的所有数据表, redis 中也会自动创建好相关的数据。
sentry upgrade 执行中会询问是否创建用户:
Would you like to create a user account now? [Y/n]:
我们选择创建,然后根据提示输入用户邮箱和密码就行啦。
sentry web \ worker \ cron
接下来我们就可以完整的部署 sentry了,完整的 stack yaml:
version: '3.7'
networks:
yanshi-network:
external: true
services:
cli:
image: sentry:9.1.2
networks:
- yanshi-network
volumes:
- /mnt/sentry/conf:/etc/sentry/
stdin_open: true # -i interactive
tty: true # -t tty
privileged: true
entrypoint: ["sh"] # 执行 sh
server:
image: sentry:9.1.2
privileged: true
restart: unless-stopped
networks:
- yanshi-network
volumes:
- /mnt/sentry/data:/var/lib/sentry/files
- /mnt/sentry/conf:/etc/sentry/
command: /bin/bash -c "sentry run web"
environment:
C_FORCE_ROOT: "true"
ports:
- "9000:9000"
cron:
image: sentry:9.1.2
privileged: true
restart: unless-stopped
networks:
- yanshi-network
volumes:
- /mnt/sentry/data:/var/lib/sentry/files
- /mnt/sentry/conf:/etc/sentry/
command: /bin/bash -c "sentry run cron"
environment:
C_FORCE_ROOT: "true"
worker:
image: sentry:9.1.2
privileged: true
restart: unless-stopped
networks:
- yanshi-network
volumes:
- /mnt/sentry/data:/var/lib/sentry/files
- /mnt/sentry/conf:/etc/sentry/
command: /bin/bash -c "sentry run worker"
environment:
C_FORCE_ROOT: "true"
部署完成后就可以通过 http://ip:9000 访问sentry了,输入用户密码登录。
坎坷
- sentry upgrade 时报错:django.db.utils.OperationalError: FATAL: database “sentry” does not exist
没有在postgreSql中创建好对应的数据库,手动创建后就没问题了。 - sentry upgrade 创建用户时选择了N,没有用户登录
这个可以通过 sentry createuser 来创建用户。 - 在管理页面测试邮件发送失败(连接超时)。
这个是我配置的 mail.port 写错了。 - 在管理页面测试邮件发送正常,但邀请成员邮件发送失败。
查看日志发现如下报错:
16:10:49 [WARNING] sentry.utils.geo: settings.GEOIP_PATH_MMDB not configured.
16:10:52 [INFO] sentry.plugins.github: apps-not-configured
16:10:52 [INFO] sentry.bgtasks: bgtask.spawn (task_name=u'sentry.bgtasks.clean_dsymcache:clean_dsymcache')
-------------- celery@a6d25dd3513d v3.1.18 (Cipater)
---- **** -----
--- * *** * -- Linux-3.10.0-1160.66.1.el7.x86_64-x86_64-with-debian-9.11
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: sentry:0x7f055f43f150
- ** ---------- .> transport: redis://:**@redis:6379/2
- ** ---------- .> results: disabled
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ----
--- ***** ----- [queues]
-------------- .> activity.notify exchange=default(direct) key=activity.notify
.> alerts exchange=default(direct) key=alerts
.> app_platform exchange=default(direct) key=app_platform
.> assemble exchange=default(direct) key=assemble
.> auth exchange=default(direct) key=auth
.> buffers.process_pending exchange=default(direct) key=buffers.process_pending
.> cleanup exchange=default(direct) key=cleanup
.> commits exchange=default(direct) key=commits
.> counters-0 exchange=counters(direct) key=
.> default exchange=default(direct) key=default
.> digests.delivery exchange=default(direct) key=digests.delivery
.> digests.scheduling exchange=default(direct) key=digests.scheduling
.> email exchange=default(direct) key=email
.> events.index_event_tags exchange=default(direct) key=events.index_event_tags
.> events.preprocess_event exchange=default(direct) key=events.preprocess_event
.> events.process_event exchange=default(direct) key=events.process_event
.> events.reprocess_events exchange=default(direct) key=events.reprocess_events
.> events.reprocessing.preprocess_event exchange=default(direct) key=events.reprocessing.preprocess_event
.> events.reprocessing.process_event exchange=default(direct) key=events.reprocessing.process_event
.> events.save_event exchange=default(direct) key=events.save_event
.> files.delete exchange=default(direct) key=files.delete
.> integrations exchange=default(direct) key=integrations
.> merge exchange=default(direct) key=merge
.> options exchange=default(direct) key=options
.> reports.deliver exchange=default(direct) key=reports.deliver
.> reports.prepare exchange=default(direct) key=reports.prepare
.> search exchange=default(direct) key=search
.> sleep exchange=default(direct) key=sleep
.> stats exchange=default(direct) key=stats
.> triggers-0 exchange=triggers(direct) key=
.> unmerge exchange=default(direct) key=unmerge
.> update exchange=default(direct) key=update
Traceback (most recent call last):
File "/usr/local/lib/python2.7/site-packages/sentry/digests/backends/redis.py", line 191, in maintenance
self.__maintenance_partition(host, deadline, timestamp)
File "/usr/local/lib/python2.7/site-packages/sentry/digests/backends/redis.py", line 181, in __maintenance_partition
deadline,
File "/usr/local/lib/python2.7/site-packages/sentry/utils/redis.py", line 239, in call_script
return script(keys, args, client)
File "/usr/local/lib/python2.7/site-packages/redis/client.py", line 2699, in __call__
return client.evalsha(self.sha, len(keys), *args)
File "/usr/local/lib/python2.7/site-packages/redis/client.py", line 1944, in evalsha
return self.execute_command('EVALSHA', sha, numkeys, *keys_and_args)
File "/usr/local/lib/python2.7/site-packages/redis/client.py", line 573, in execute_command
return self.parse_response(connection, command_name, **options)
File "/usr/local/lib/python2.7/site-packages/redis/client.py", line 585, in parse_response
response = connection.read_response()
File "/usr/local/lib/python2.7/site-packages/redis/connection.py", line 582, in read_response
raise response
ResponseError: user_script:11: Attempt to modify a readonly table script: 094f8735408af273da283389ad983f63977831e8, on @user_script:11.
16:10:57 [ERROR] sentry.digests: Failed to perform maintenance on digest partition 0 due to error: ResponseError('user_script:11: Attempt to modify a readonly table script: 094f8735408af273da283389ad983f63977831e8, on @user_script:11.',)
Traceback (most recent call last):
File "/usr/local/lib/python2.7/site-packages/sentry/digests/backends/redis.py", line 162, in schedule
for key, timestamp in self.__schedule_partition(host, deadline, timestamp):
File "/usr/local/lib/python2.7/site-packages/sentry/digests/backends/redis.py", line 152, in __schedule_partition
deadline,
File "/usr/local/lib/python2.7/site-packages/sentry/utils/redis.py", line 239, in call_script
return script(keys, args, client)
File "/usr/local/lib/python2.7/site-packages/redis/client.py", line 2694, in __call__
return client.evalsha(self.sha, len(keys), *args)
File "/usr/local/lib/python2.7/site-packages/redis/client.py", line 1944, in evalsha
return self.execute_command('EVALSHA', sha, numkeys, *keys_and_args)
File "/usr/local/lib/python2.7/site-packages/redis/client.py", line 573, in execute_command
return self.parse_response(connection, command_name, **options)
File "/usr/local/lib/python2.7/site-packages/redis/client.py", line 585, in parse_response
response = connection.read_response()
File "/usr/local/lib/python2.7/site-packages/redis/connection.py", line 582, in read_response
raise response
ResponseError: user_script:11: Attempt to modify a readonly table script: 094f8735408af273da283389ad983f63977831e8, on @user_script:11.
16:10:57 [ERROR] sentry.digests: Failed to perform scheduling for partition 0 due to error: ResponseError('user_script:11: Attempt to modify a readonly table script: 094f8735408af273da283389ad983f63977831e8, on @user_script:11.',)
后来google发现是redis版本太新,兼容性问题,换redis6.0后正常。