资讯动态

docker-compose一键部署jira-software:从yaml到生产环境完整实践

发布时间:2026/10/19 11:05:30 来源:尧图企业网站定制
聊聊docker-compose一键部署jira-software这件事。很多团队的Jira都是这么长起来的先是在某个负责人的笔记本上跑着大家图个省事人多了就挪到一台公用服务器装好Java、下安装包、排队配置数据库再后来要升级、要迁移、要换机器每一步都像拆炸弹。真正用Docker Compose把Jira Software跑起来之后我才觉得自建项目管理工具的部署基线终于是可复现的了——一个yaml文件描述所有服务一条命令拉起一条命令停掉坏了也能快速重来。这篇文章会从选型、compose文件、初始化配置讲到日常备份和升级适合正在评估自建Jira的运维、后端同学也适合已经被乱七八糟的部署折磨过、想推倒重来的朋友。1. 为什么绕开安装包和单容器最终选了Compose编排1.1 传统安装部署的几个常见问题Jira本身是Java应用对JDK版本、JVM参数、可用内存都相当敏感。用官方安装包部署时你得先确认系统里装的是哪个版本的Java配置JAVA_HOME再手动设置堆内存参数。环境稍有不同启动日志里就可能冒出一堆莫名其妙的异常。这还只是应用本身数据库那边更麻烦PostgreSQL装在哪、字符集是什么、谁能连它、怎么网络互通全都要手工协调。装好之后还有系统服务的问题。早期很多教程让你直接./start-jira.sh服务器一重启Jira就没了后来大家学会写init脚本或者systemd unit但不同发行版的服务配置写法又不一样。最头疼的是升级官方安装包版本更新后旧数据要迁移插件要兼容性测试如果当年装的时候路径和参数没记下来升级基本靠猜。还有目录混乱。有人装在临时目录下家目录背在一个同事的迁移文档里有人让数据库和应用共用一台机器却把数据库监听地址放开到所有网卡内网还好说暴露到外网就是风险。这些坑不是不能避免但每个团队都要踩一遍才长记性。1.2 Compose解决了哪几个实际问题Compose做的不是玄学就是把以前手工维护的环境状态变成声明式配置。JDK版本、运行用户、端口、JVM参数都在镜像里固化数据库和应用各是一个service通过项目内的独立网络互通。我实际用下来最大的收益是三点。第一组件关系被写清楚了Jira依赖数据库depends_on声明顺序两个容器之间用服务名访问不用再去查对方IP。第二生命周期统一了重启策略写在compose文件里服务器开机后两个容器自动拉起不用分开管。第三也是最关键的整套环境可以复制一个yaml加两个数据目录拷到新机器里就能原样恢复不用再花半天装环境。对比单容器方案只跑一个Jira容器数据库还得单独docker run端口、网络、重启策略全靠记忆时间一长依然会乱。Compose本质上就是一个轻量的编排工具把这个场景收敛得非常干净。2. 动手前先想清楚镜像、数据库、持久化这三个决策2.1 用哪个镜像为什么必须锁tag官方在公共镜像仓库里提供了atlassian/jira-software这个镜像里面已经把Java环境、时区配置、启动脚本都封装好了。很多朋友图省事直接写atlassian/jira-software:latest这个习惯在测试环境无所谓生产环境我是坚决不用的。原因是latest标签会漂移。今天部署时它是9.12过一两周docker compose pull一拉可能就变成9.14整个环境的版本在不知不觉中发生了变化。升级本身应该是一个显式动作而不是被一条命令顺带完成。所以我建议先到官方镜像的tag列表里选一个已经发布一段时间、被验证过的版本号写死在compose文件里。后面要升级就手动改这个tag回滚也只需要把tag改回去再up -d。2.2 数据库选PostgreSQL而不是内置H2Jira内置了一个H2数据库完全不用外部数据库也能把服务跑起来。H2的好处是省事但它的定位其实是让你下载之后先体验一下界面的并发能力一般数据文件和Jira home捆绑在一起真到生产环境很容易被并发拖垮。更关键的是很多插件对H2的支持都不好。Jira生态里那些流程插件、报表插件文档里基本都写着生产环境推荐用PostgreSQL或MySQL。在两个外部数据库之间选的话我倾向于PostgreSQL。不是说MySQL不行而是PostgreSQL对Jira的兼容性测试做得比较全字符集、排序规则这些细节坑更少。如果你没有历史包袱选PostgreSQL是最省心的路径。2.3 数据卷挂载命名卷和目录绑定的取舍数据挂载有两种常见方式。一种是命名卷由Docker自己管理物理位置docker compose down不会删数据但备份的时候需要额外导出迁移不太直观。另一种是bind mount直接把宿主机的目录挂进容器备份就是打包目录换机器就是把目录带走。我自己喜欢用bind mount目录规划成jira/ ├── .env ├── docker-compose.yml └── data/ ├── jira-home/ └── postgres/这样所有持久化数据都在一个data目录里备份策略非常清晰。有一点要注意容器里的进程是以特定uid运行的如果宿主目录的属主和权限不对容器启动时可能没有写权限。看到权限类报错时先确认容器进程的uid再在宿主机上chown一下对应目录问题一般就解决了。2.4 资源、时区与中文界面Jira是吃内存的大户。官方建议按用户规模来设置JVM堆即使小团队JVM_MINIMUM_MEMORY设置为2048m比较稳妥上限可以放到3072m或4096m。系统本身的内存要能容纳JVM加PostgreSQL的占用我一般会保证机器至少4G内存起步。时区问题也容易被漏掉。容器默认是UTC如果不设置Jira里记录的时间会比你本地时间差8小时。在compose文件里给两个服务都加上TZ环境变量就行了。中文界面就更有意思了。Jira官方镜像默认是英文要切成中文常见做法是通过JVM参数指定语言区域把-Duser.languagezh -Duser.countryCN传给Java进程。如果你团队习惯英文界面反而更顺手去掉这两个参数即可。3. compose文件这样写每一行都讲清楚3.1 先规划好项目目录部署前先建一个独立目录我习惯叫它jira/里面放compose文件、环境变量文件和数据目录。这样整个应用的所有东西都集中在一处后面做备份、迁移、清理都省心。创建完目录后先手动把data/jira-home和data/postgres两个目录建出来。如果启动时遇到权限问题根据容器日志提示的uid在宿主机上调整属主这里没必要在部署前猜一个数字。3.2 完整docker-compose.yml这是我在实际部署中使用的compose文件版本号和密码部分按你自己的环境替换services: jira: image: atlassian/jira-software:9.12.5 container_name: jira restart: unless-stopped ports: - 8080:8080 volumes: - ./data/jira-home:/var/atlassian/application-data/jira environment: TZ: Asia/Shanghai JVM_MINIMUM_MEMORY: 2048m JVM_MAXIMUM_MEMORY: 4096m JVM_SUPPORT_RECOMMENDED_ARGS: - -Duser.languagezh -Duser.countryCN -Dfile.encodingUTF-8 depends_on: - jira-db networks: - jira-network jira-db: image: postgres:16-alpine container_name: jira-db restart: unless-stopped environment: TZ: Asia/Shanghai POSTGRES_DB: jiradb POSTGRES_USER: jirauser POSTGRES_PASSWORD: change_this_password POSTGRES_INITDB_ARGS: --localeen_US.UTF-8 --encodingUTF8 volumes: - ./data/postgres:/var/lib/postgresql/data networks: - jira-network networks: jira-network: driver: bridge当前主流的Docker Compose V2已经不需要version字段了直接写services就好。你可以根据自己的Compose版本决定是否保留version: 3。这里用的镜像版本9.12.5是一个示例正式部署前要到官方镜像仓库确认一个你想用的具体版本号。3.3 关键字段为什么要这么写先看Jira这个服务。container_name写死了容器名好处是日志和命令操作时比较直观restart: unless-stopped意味着服务器重启后容器会自动起来这是生产环境我最看重的一个策略。端口映射8080:8080对应Jira的默认HTTP端口如果宿主机的8080被占用了可以改成18080:8080这样的形式访问时带对应端口。volumes把./data/jira-home挂到了容器里的Jira home目录。这个home目录存放了Jira的配置、附件、插件和搜索索引是绝对不能丢的部分。数据库容器的数据目录挂在./data/postgres下。两个目录对应两个服务各自的持久化数据职责明确。depends_on只是控制容器的启动顺序它不会等数据库“完全就绪”。也就是说Jira容器起来的时候PostgreSQL可能还在初始化。不用担心Jira的启动脚本本身会尝试连接数据库配合restart: unless-stopped连不上时会自动重启容器重试。数据库这边有几个细节值得单独说。POSTGRES_DB、POSTGRES_USER、POSTGRES_PASSWORD分别是Jira要使用的库名、用户名和密码后面配置向导里要填的就是这三个值。POSTGRES_INITDB_ARGS这个参数特别容易被忽略它指定了PostgreSQL初始化数据目录时的语言环境和字符集。如果你没有指定en_US.UTF-8数据库默认的排序规则会给你后面中文内容的存储和排序埋下隐患。3.4 拉取镜像与启动命令搭建好目录和compose文件后先做一次语法检查cd jira docker compose configconfig命令会解析并输出最终的配置如果yaml有语法错误或字段写错这一步就会报出来。确认无误后拉取镜像并启动docker compose pull docker compose up -d第一次拉镜像可能要花点时间取决于网络状况。启动后查看状态docker compose ps docker compose logs -f jira如果两个服务都是Up状态就可以继续配置向导了。如果你还在用老版的docker-compose命令以上命令前加横线即可本质上一样。不过新版Docker都内置了docker compose子命令我建议直接用新版。4. 启动后的初始化配置和常见报错排查4.1 第一次访问后的配置向导怎么填容器启动后浏览器访问http://服务器IP:8080。如果本地部署就是http://localhost:8080端口号和你compose里映射的宿主端口保持一致。首页会出现一个欢迎界面让你选择安装模式。如果你需要完全掌控配置选择手动配置那种模式即可另一种模式会引导你一步步设置数据源。这时候关键步是数据库连接数据库类型选PostgreSQLJDBC连接串写成jdbc:postgresql://jira-db:5432/jiradb。这里的jira-db是compose网络里的服务名不用写成IP地址。用户名填jirauser密码填compose文件里的POSTGRES_PASSWORD。点击测试连接如果能通说明Jira和数据库之间的链路正常。如果提示缺少数据库驱动先看看镜像里是否已经带了PostgreSQL JDBC驱动新版Jira一般自带很少需要手动下载驱动放到jira-home/lib目录。数据库连接通过后继续设置应用标题和Base URL。Base URL这里要特别注意如果你以后准备用域名访问现在就填最终的域名不然后面Jira生成的邮件链接、页面跳转都会指向错误的地址。授权环节可以先用官方试用模式走通流程正式投入使用前再补充合法许可信息。4.2 我排查过的几个高频错误部署Jira的过程中有几个问题出现频率特别高这里集中列一下现象常见原因与处理方式Jira容器反复重启最常见是JVM内存不足系统总内存要满足JVM加PostgreSQL的占用。查看日志出现OOM时调大JVM_MINIMUM_MEMORY或给服务器加内存/swap。数据库连接失败最常见是depends_on只等容器启动、不等数据库就绪。靠restart: unless-stopped自动重试同时核对compose里的数据库密码和向导里填写的密码是否一致。启动时权限报错data/jira-home或data/postgres目录属主不对。确认容器内进程uid后在宿主机上chown对应目录即可恢复。宿主机访问端口不通检查ports映射是否写成了8080而不是18080:8080这种形式同时确认防火墙或安全组放行了对应端口。界面时间少了8小时容器没设置TZ环境变量。补上Asia/Shanghai后重启容器。这里的每个问题我基本都亲手踩过尤其是第一次部署时内存配置给得太小容器一直OOM重启一开始还以为是数据库连接不上绕了很大一圈才定位到JVM参数上。所以建议你在启动前就把JVM_MINIMUM_MEMORY和系统内存对齐。4.3 如何判断部署真的成功了不要只看容器是Up状态就宣布成功。我更习惯做三层检查。第一层看进程状态docker compose ps输出里两个服务的状态都是Up且没有Restarting字样。第二层看日志docker compose logs -f jira里出现Jira已经启动完成、端口开始监听之类的信息。第三层看页面浏览器打开欢迎界面能进入配置向导并成功保存设置这才算真正打通了。如果你是在内网环境部署最后顺手确认一下数据库的数据是否真的落到了宿主目录查看data/postgres下有没有PG_VERSION之类的文件以及data/jira-home里是否开始生成配置目录。看到这些文件出现说明持久化生效了。5. 上线一周后最好补上的运维细节5.1 备份pg_dump加文件快照双保险Jira的数据其实分两部分一部分在数据库里比如项目、问题、工作流一部分在Jira home目录里比如附件、插件配置、搜索索引。备份必须两手抓。数据库备份最简单的方案是直接用pg_dump导出docker compose exec -T jira-db pg_dump -U jirauser jiradb jiradb_$(date %F_%H%M).sql这会把数据库导出成一个SQL文件恢复的时候用psql导回去就行。文件备份更简单bind mount方式下直接把data/目录打包tar czf jira_backup_$(date %F_%H%M).tar.gz data/我习惯每次备份时顺手在备份目录里放一个VERSION文件记录当时的Jira版本和PostgreSQL版本。这样恢复时能明确知道compose文件里该填哪个镜像tag避免版本错配。数据库备份每天跑一次文件备份在变更操作前手动做一次基本够用。5.2 升级版本的正确姿势Jira升级本身不算复杂但顺序一定要对。第一步永远是完整备份数据库和home目录缺一不可因为Jira升级后数据库schema和索引结构都可能被改动一旦升级完成想降级回旧版本往往十分困难。备份做完了修改compose文件里的镜像tag然后执行docker compose pull docker compose up -d启动后观察日志如果Jira检测到数据版本比当前程序版本旧通常会自动进入升级流程可能还会看到数据库结构变更的提示。升级完成后再清理旧镜像docker image prune -f这里最想强调的还是那句话不要在备份不完整的情况下升级。另外如果生产环境数据很重要最好先在一个临时环境里跑一遍升级流程确认插件兼容后再动生产。5.3 日志、卷和资源清理Jira运行时间长了日志和镜像会慢慢占满磁盘。容器日志如果不加限制会一直往宿主机的json-file里写。给服务增加一个日志轮转配置是个一劳永逸的办法logging: driver: json-file options: max-size: 20m max-file: 5Jira自身的日志在data/jira-home/log目录下如果发现这个目录越来越大可以配合计划任务定期清理超过30天的旧日志。删除前确认一下Jira正在使用哪些文件别把当天的日志也删了。镜像和临时数据可以用docker system df定期查看占用情况docker image prune清理悬空镜像docker volume prune要谨慎使用它会把所有未挂载的卷都清掉除非你确认数据已经备份否则不要轻易执行。5.4 前端接入网关和HTTPS的简单建议如果Jira要面向公网或跨部门长期使用不太建议把8080端口直接暴露出去。常见的做法是在前面加一层Nginx或Caddy这类入口服务做TLS终结让用户通过https://jira.你的域名访问。容器内部仍然跑HTTP由网关负责加密。这里有个容易踩的坑Jira管理后台里的Base URL必须改成对外访问的HTTPS域名否则页面上生成的项目链接、通知邮件里的地址都会变成容器内部地址用户点了根本打不开。修改Base URL的位置在Jira管理设置里改完保存后建议重新登录一次验证各类跳转。如果你多个服务都在这台机器上跑网关还能顺便做路径转发、负载分发、访问控制。毕竟Jira这种承载着团队日常协作的工具稳定运行比什么都重要入口收敛一下总是更安心。最后分享一点实际体会。最初给一个团队搭Jira时最容易被忽略的不是yaml怎么写而是数据库的locale参数和Jira home目录的权限。这两个问题一个影响长远的中文数据排序一个直接影响容器能否启动偏偏在部署初期最容易藏起来。docker-compose一键部署jira-software真正的价值不只是省掉安装步骤而是让整个环境的基线变得可复现无论什么时间、换到哪台机器一条up -d拉起来的环境都是一样的。如果你正打算把Jira从某台临时服务器里解放出来不妨照着这个方案试一次把环境和数据彻底理清楚后续的升级、备份、迁移就都不慌了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑