docker基于minio部署outline团队知识库

news2025/1/6 9:21:27

outline 介绍

Outline 是一个开源的Wiki 知识库和团队协作文档管理工具,美观、实时协作、功能丰富且兼容 Markdown,设计用于帮助团队和组织有效地创建、共享和管理文档。

Outline 具有简单易用的界面和强大的功能,可以替代传统的文档管理系统,如 Google Docs 或 Confluence。Outline 提供了一种结构化的方式来组织信息,使团队成员可以快速访问和协作内容。

在这里插入图片描述

主要特性:

  • ✏️ 直观的编辑体验:一个极快的编辑器,支持 Markdown、斜杠命令、交互式嵌入等等
  • 👥 多人协作:与团队成员实时协作处理文档。评论和话题让对话井井有条。
  • 🔍 强大的搜索和问答功能:立即在您的工作空间中进行搜索,并提出有关文档的问题以获得直接的 AI 答案。
  • 💬 与 Slack 集成:无需离开聊天即可搜索、共享文档并提出问题。文档更新时向频道发布通知。
  • 🌐 公开分享:通过链接公开共享文档,或与团队私下共享文档。使用您自己的品牌颜色、徽标和域名。**

其他特性:

  • 速度极快:Outline 速度很快,真的很快。努力确保毫秒级响应时间 - 文档立即加载、搜索快速、用户界面导航快捷。
  • 🤝 协作性:Outline 经过精心设计,功能强大、实时且易于使用。阅读和编写文档应该是一件令人愉快的事情。
  • 🌙 深色模式:对于夜猫子来说,我们已经为您提供了帮助。 Outline 具有漂亮的深色模式,既养眼又美观。
  • 🔒 安全和权限:通过读写权限、用户组、来宾用户、公共共享等管理知识库。
  • 🛠️ 20+ 集成:简单集成到您日常使用的工具中,例如 Slack、Figma、Loom 等。找不到您需要的集成?还有一个开放的 API 。
  • 🌍 用您的语言:Outline 支持 RTL,包括 17 种语言的翻译,包括 🇫🇷 法语、🇪🇸 西班牙语、🇩🇪 德语、🇰🇷 韩语和 🇨🇳 中文。
  • 🚀 建于公共场所:Outline 会定期更新新功能和修复,请查看我们的公共变更日志以了解进展情况!
  • 🛠️ 开源:Outline 的源代码是公开的,开发是公开完成的。更喜欢托管在您自己的基础设施上?没问题。
  • 🖌️ 可定制:自定义域允许您拥有 docs.yourteam.com 。带有您自己的品牌和颜色的白色标签。

官方网站:https://www.getoutline.com/

项目地址:https://github.com/outline/outline

outline 部署规划

我们将采用分步部署的方式,依次通过docker-compose安装traefik、minio、keyclock及outline组件,主要涉及docker-compose .env环境变量文件的定义及docker-compose.yaml文件的创建。

部署前置要求:

  • 准备一台云服务器,例如 阿里云ECS服务器 或轻量服务器,本部署示例购买1台阿里云ECS服务器(包年包月购买3年具有2.6折的最低优惠),服务器配置为2核CPU/4G内存/100G磁盘,绑定公网IP,带宽按流量计费;
  • 准备操作系统,本示例使用 Ubuntu 22.04 LTS 操作系统;
  • 准备可用域名,并配置好域名解析,本示例使用阿里云域名;
  • -SSL证书,由traefik通过Let's Encrypt自动申请免费证书;
  • 主机上已安装 dockerdocker compose

整体部署架构图:
在这里插入图片描述

部署服务组件清单:

我们采用 Traefik 作为反向代理和负载均衡器,MinIO 作为对象存储,Keycloak 作为身份和访问管理工具,并且利用 PostgreSQLRedis 作为数据库和缓存,来支撑 Outline 的运行。

名称说明版本
Traefik现代的反向代理和负载均衡器,用于管理和路由 HTTP 请求,提供 SSL 终止和路径路由功能。v3.1
MinIO高性能的对象存储服务,兼容 AWS S3 API,Outline 用于存储文件和附件。RELEASE.2024-08-26T15-33-07Z
Keycloak开源的身份和访问管理工具,用于提供单点登录和身份认证功能,支持 OAuth2 和 SAML 协议。25.0.4
Outline开源的知识库和文档管理工具,用于团队协作、文档编辑和知识共享。0.78.0
Redis高性能的内存数据存储,用于缓存和会话管理,提高应用性能。7.4.0
PostgreSQL开源的关系型数据库管理系统,用于存储 Outline 的持久化数据。16.2

Outline文件存储选择

Outline文件存储支持以下两种形式,本示例采用minio S3存储

  • Local file system:如果希望将文件上传存储在运行 Outline 的同一服务器上,则可以使用本地文件系统存储选项来实现。
  • AWS S3:由于AWS S3是对象存储的标准,因此不一定使用云上的AWS S3存储,例如可以通过自建minio来实现,完整的支持列表见下表。

Outline 可以与绝大多数 S3 兼容的 API 一起使用,因为使用的是可用 API 接口的一个非常小的子集,以下内容已经过社区成员的测试。

ServiceCompatible
Amazon S3
Minio
DigitalOcean Object Storage
Alibaba Cloud / Aliyun OSS✅ (discussion)
Scaleway✅ (discussion)
Cloudflare R2❌ (discussion)
Backblaze❌ (discussion)
OVH Object Storage

身份验证提供程序选择

Outline 可以配置为接受各种 SSO、OIDC 和 SAML 身份验证选项,具体取决于所使用的版本,本部署示例使用支持OIDC的keycloak

  • Google
  • Microsoft / Azure
  • Slack
  • OIDC
  • Discord
  • GitLab
  • Email magic link
  • SAML
  • Okta
  • OneLogin

注:Outline不支持邮箱+密码认证

前置配置工作

1. 配置域名解析

域名配置清单:

域名地址解析A记录值说明
https://outline.example.com120.79.11.68用于访问 Outline 应用程序的主域名,提供知识库和文档管理功能,供团队成员进行协作和编辑。
https://keycloak.example.com120.79.11.68用于访问 Keycloak 身份认证服务的域名,提供用户身份验证、授权管理和单点登录服务。
https://minio.example.com120.79.11.68用于Outline访问 MinIO 对象存储服务的域名,存储 Outline 中的文件、文档和附件,支持 S3 兼容 API 操作。
https://console.minio.example.com120.79.11.68用于访问 MinIO 管理控制台的域名,提供对 MinIO 对象存储服务的管理界面,包括用户和权限管理功能。

说明:

  • 基本域名为example.com,前缀可自定义,请将example.com域名更改为您自己的域名;
  • 示例公网IP地址 120.79.11.68 为Outline云主机的公网IP地址。

域名解析A记录示例:
在这里插入图片描述

2. 配置安全组规则

安全组规则放通清单:

端口号协议用途说明
80TCPTraefik 代理的 HTTP 端口,用于处理未加密的 Web 流量。
443TCPTraefik 代理的 HTTPS 端口,用于处理加密的 Web 流量(SSL/TLS)。

安全组配置示例
在这里插入图片描述

3. 创建目录结构

创建组件安装目录

mkdir -p /data/{traefik,minio,keycloak,outline}

确认目录结构

root@ecs01:~# apt install -y tree
root@ubuntu:~# tree /data/
/data/
├── keycloak
├── minio
├── outline
└── traefik

4 directories, 0 files

4. 创建docker网络

手动创建docker网络

docker network create traefik-network
docker network create outline-network
docker network create keycloak-network
docker network create minio-network

确认docker网络创建成功

root@ecs01:~# docker network ls
NETWORK ID     NAME               DRIVER    SCOPE
55509fbd4813   bridge             bridge    local
00b8d117c799   host               host      local
b1c5d0f0cd6d   keycloak-network   bridge    local
3af149dcc797   minio-network      bridge    local
a1e5cf67efab   none               null      local
f0f830bcea64   outline-network    bridge    local
ba512776a14a   traefik-network    bridge    local

Traefik 部署

使用以下方式生成traefikadmin密码,替换TRAEFIK_BASIC_AUTH中的值。

root@ecs01:~# apt install -y apache2-utils
root@ecs01:~# echo $(htpasswd -nbB traefikadmin "mypassword") | sed -e s/\\$/\\$\\$/g
traefikadmin:$$2y$$05$$AKU6mkLPs1EB4t3Hh5QdB.nUJgLYFqZySUpFVyJw4XSFeG.dPXveS

创建环境变量文件

cd /data/traefik
cat >/data/traefik/.env<<EOF
# Traefik Variables
TRAEFIK_IMAGE_TAG=traefik:v3.1
TRAEFIK_LOG_LEVEL=WARN
TRAEFIK_ACME_EMAIL=example@outlook.com
TRAEFIK_HOSTNAME=traefik.example.com
# Basic Authentication for Traefik Dashboard
# Username: traefikadmin
# Passwords must be encoded using MD5, SHA1, or BCrypt https://hostingcanada.org/htpasswd-generator/
TRAEFIK_BASIC_AUTH=traefikadmin:$$2y$$05$$AKU6csLPs1EB4t3Hh5QdF.nUJgLYFqasdfwerqweJw4XSFeG.dPXveS
EOF

参数说明

  • TRAEFIK_IMAGE_TAG=traefik:v3.1: 指定 Traefik 镜像的版本标签。
  • TRAEFIK_LOG_LEVEL=WARN: 设置 Traefik 的日志级别(DEBUG, INFO, WARN, ERROR)。
  • TRAEFIK_ACME_EMAIL=example@outlook.com: 用于 ACME 协议的电子邮件地址,管理 SSL 证书。
  • TRAEFIK_HOSTNAME=traefik.example.com: 指定 Traefik 仪表板的访问域名,替换为您自己的域名。
  • TRAEFIK_BASIC_AUTH: 用于保护 Traefik 仪表板的基本认证信息,格式为 用户名:加密后的密码

创建docker-compose文件

cat >/data/traefik/docker-compose.yaml<<'EOF'
name: traefik

networks:
  traefik-network:
    external: true

volumes:
  traefik-certificates:

services:
  traefik:
    image: ${TRAEFIK_IMAGE_TAG}
    command:
      - "--log.level=${TRAEFIK_LOG_LEVEL}"
      - "--accesslog=true"
      - "--api.dashboard=true"
      - "--api.insecure=true"
      # Docker Provider
      - "--providers.docker=true"
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - "--providers.docker.exposedByDefault=false"
      # health check
      - "--ping=true"
      - "--ping.entrypoint=ping"
      - "--entryPoints.ping.address=:8082"
      # letsencrypt
      - "--entryPoints.websecure.address=:443"
      - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
      - "--certificatesresolvers.letsencrypt.acme.email=${TRAEFIK_ACME_EMAIL}"
      - "--certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/acme.json"
      # dashboard-redirect-https
      - "--entryPoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--entrypoints.web.http.redirections.entryPoint.scheme=https"
      - "--entrypoints.web.http.redirections.entrypoint.permanent=true"
      # prometheus   
      - "--metrics.prometheus=true"
      - "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0"
      - "--global.checkNewVersion=true"
      - "--global.sendAnonymousUsage=false"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - traefik-certificates:/etc/traefik/acme
    networks:
      - traefik-network
    ports:
      - "80:80"
      - "443:443"
    healthcheck:
      test: ["CMD", "wget", "http://localhost:8082/ping","--spider"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 5s
    labels:
      - "traefik.enable=true"
      # dashboard with https
      - "traefik.http.routers.dashboard.rule=Host(`${TRAEFIK_HOSTNAME}`)"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.entrypoints=websecure"
      - "traefik.http.services.dashboard.loadbalancer.server.port=8080"
      - "traefik.http.routers.dashboard.tls=true"
      - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
      - "traefik.http.services.dashboard.loadbalancer.passhostheader=true"
      # basic auth
      - "traefik.http.routers.dashboard.middlewares=authtraefik"
      - "traefik.http.middlewares.authtraefik.basicauth.users=${TRAEFIK_BASIC_AUTH}"
      # service-redirect-https   
      - "traefik.http.routers.http-catchall.rule=HostRegexp(`{host:.+}`)"
      - "traefik.http.routers.http-catchall.entrypoints=web"
      - "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
    restart: unless-stopped
EOF

启动traefik容器

docker compose up -d

确认容器运行状态

root@ecs01:/data/traefik# docker compose ps
NAME                IMAGE          COMMAND                  SERVICE   CREATED         STATUS                   PORTS
traefik-traefik-1   traefik:v3.1   "/entrypoint.sh --lo…"   traefik   3 minutes ago   Up 2 minutes (healthy)   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp
root@ecs01:/data/traefik# 

浏览器访问traefik dashboard: https://traefik.example.com,输入traefik登录账号traefikadmin及设置的密码。
在这里插入图片描述

正常登录后如下:
在这里插入图片描述

Minio部署

创建环境变量文件

cd /data/minio
cat >/data/minio/.env<<EOF
# Minio Variables
MINIO_IMAGE_TAG=minio/minio:RELEASE.2024-08-26T15-33-07Z
MINIO_ADMIN=minioadmin
MINIO_ADMIN_PASSWORD=minioadmin
# MiniIO API hostname
MINIO_HOSTNAME=minio.example.com
MINIO_CONSOLE_URL=https://console.minio.example.com
MINIO_CONSOLE_HOSTNAME=console.minio.example.com
# Minio for Outline
OUTLINE_MINIO_BUCKET_NAME=outline
OUTLINE_MINIO_USER=bucket.outline
OUTLINE_MINIO_USER_PASSWORD=outlinepass
EOF

参数说明

  • MINIO_IMAGE_TAG: 指定 MinIO 镜像的版本标签,表示使用的 MinIO 版本。

  • MINIO_ADMIN=minioadmin: MinIO 的管理员用户名,示例值为 minioadmin

  • MINIO_ADMIN_PASSWORD=minioadmin: MinIO 的管理员密码,示例值为 minioadmin

  • MINIO_HOSTNAME=minio.example.com: 指定 MinIO 服务的主机名,用于通过域名访问 MinIO API,替换为您自己的域名。

  • MINIO_CONSOLE_URL=https://console.minio.example.com: 指定 MinIO 控制台的完整 URL,用于访问 MinIO Web 管理界面,替换为您自己的域名。

  • MINIO_CONSOLE_HOSTNAME=console.minio.example.com: 指定 MinIO 控制台的主机名,用于配置 Traefik 代理的路由或域名解析,替换为您自己的域名。

  • OUTLINE_MINIO_BUCKET_NAME=outline:指定 Outline 在 MinIO 中使用的存储桶名称。这个存储桶用于存储 Outline 的文件、文档和附件,是一个用于组织和管理所有 Outline 相关数据的存储容器。

  • OUTLINE_MINIO_USER=bucket.outline:设置访问 MinIO 存储桶的用户名。通常以“bucket.”作为前缀,表示该用户对 OUTLINE_MINIO_BUCKET_NAME 中指定的存储桶具有特定的访问权限。

  • OUTLINE_MINIO_USER_PASSWORD=outlinepass:这是与 MinIO 用户 (bucket.outline) 关联的密码,用于认证和授权访问 Outline 指定的 MinIO 存储桶。

创建docker-compose文件

cat >/data/minio/docker-compose.yaml<<'EOF'
name: minio

networks:
  minio-network:
    external: true
  traefik-network:
    external: true

volumes:
  minio-data:

services:
  minio:
    image: ${MINIO_IMAGE_TAG}
    command: minio server /data --console-address ":9001"
    volumes:
      - minio-data:/data
    environment:
      MINIO_ROOT_USER: ${MINIO_ADMIN}
      MINIO_ROOT_PASSWORD: ${MINIO_ADMIN_PASSWORD}
      MINIO_BROWSER_REDIRECT_URL: ${MINIO_CONSOLE_URL}
    networks:
      - minio-network
      - traefik-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 60s
    labels:
      - "traefik.enable=true"
      # Minio API
      - "traefik.http.routers.minio-api.rule=Host(`${MINIO_HOSTNAME}`)"
      - "traefik.http.routers.minio-api.service=minio-api"
      - "traefik.http.routers.minio-api.entrypoints=websecure"
      - "traefik.http.services.minio-api.loadbalancer.server.port=9000"
      - "traefik.http.routers.minio-api.tls=true"
      - "traefik.http.routers.minio-api.tls.certresolver=letsencrypt"
      - "traefik.http.services.minio-api.loadbalancer.passhostheader=true"
      - "traefik.http.routers.minio-api.middlewares=compresstraefik"
      # Minio Console
      - "traefik.http.routers.minio-console.rule=Host(`${MINIO_CONSOLE_HOSTNAME}`)"
      - "traefik.http.routers.minio-console.service=minio-console"
      - "traefik.http.routers.minio-console.entrypoints=websecure"
      - "traefik.http.services.minio-console.loadbalancer.server.port=9001"
      - "traefik.http.routers.minio-console.tls=true"
      - "traefik.http.routers.minio-console.tls.certresolver=letsencrypt"
      - "traefik.http.services.minio-console.loadbalancer.passhostheader=true"
      - "traefik.http.routers.minio-console.middlewares=compresstraefik"
      - "traefik.http.middlewares.compresstraefik.compress=true"
      - "traefik.docker.network=traefik-network"
    restart: unless-stopped
EOF

启动minio容器

docker compose up -d

确认容器运行状态

root@ecs01:/data/minio# docker compose ps
NAME            IMAGE                                      COMMAND                  SERVICE   CREATED       STATUS                 PORTS
minio-minio-1   minio/minio:RELEASE.2024-08-26T15-33-07Z   "/usr/bin/docker-ent…"   minio     4 hours ago   Up 4 hours (healthy)   9000/tcp

浏览器访问minio console控制台: https://console.minio.example.com,输入minio登录账号minioadmin及设置的密码。

登录后示例如下:
在这里插入图片描述

Minio配置

安装minio客户端,可以从官网下载或从容器取出客户端文件

root@ecs01:/data/minio# docker cp minio-minio-1:/usr/bin/mc /usr/local/bin/

为outline创建存储桶及minio用户

定义minio配置变量,在当前shell执行以下命令

cd /data/minio
source .env

配置 minio 本地访问

mc config host add minio https://${MINIO_HOSTNAME} ${MINIO_ADMIN} ${MINIO_ADMIN_PASSWORD}

为outline创建单独的minio存储桶及用户

mc mb minio/${OUTLINE_MINIO_BUCKET_NAME}
mc admin user add minio ${OUTLINE_MINIO_USER} ${OUTLINE_MINIO_USER_PASSWORD}

为outline创建单独的minio访问策略

mkdir -p /data/minio/outline_policys
cd /data/minio/outline_policys
cat > outline-policy.json <<-EOF
  {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Action": [
          "s3:GetBucketLocation",
          "s3:ListBucket",
          "s3:ListBucketMultipartUploads"
        ],
        "Resource": [
          "arn:aws:s3:::${OUTLINE_MINIO_BUCKET_NAME}"
        ]
      },
      {
        "Action": [
          "s3:AbortMultipartUpload",
          "s3:DeleteObject",
          "s3:GetObject",
          "s3:ListMultipartUploadParts",
          "s3:PutObject",
          "s3:GetObject"
        ],
        "Effect": "Allow",
        "Resource": [
          "arn:aws:s3:::${OUTLINE_MINIO_BUCKET_NAME}/*"
        ],
        "Sid": ""
      }
    ]
  }
EOF
cat > outline-public.json <<-EOF
  {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": {
        "AWS": [
          "*"
        ]
      },
        "Action": [
          "s3:GetObject",
          "s3:ListMultipartUploadParts"
        ],
        "Resource": [
          "arn:aws:s3:::${OUTLINE_MINIO_BUCKET_NAME}/public/*"
        ]
      }
    ]
  }
EOF

应用策略

mc anonymous set-json outline-public.json minio/${OUTLINE_MINIO_BUCKET_NAME}
mc admin policy create minio OutlineAppFullAccess outline-policy.json
mc admin policy attach minio OutlineAppFullAccess --user=${OUTLINE_MINIO_USER}

确认存储桶已创建
在这里插入图片描述

keycloak部署

创建环境变量文件

cd /data/keycloak
cat >/data/keycloak/.env<<EOF
# Keycloak Variables
KEYCLOAK_POSTGRES_IMAGE_TAG=docker.io/library/postgres:16.2
KEYCLOAK_IMAGE_TAG=docker.io/keycloak/keycloak:25.0.4
KEYCLOAK_DB_NAME=keycloakdb
KEYCLOAK_DB_USER=keycloakdbuser
KEYCLOAK_DB_PASSWORD=keycloakdbpass
KEYCLOAK_ADMIN_USERNAME=keycloakadmin
KEYCLOAK_ADMIN_PASSWORD=keycloakadminpass
KEYCLOAK_HOSTNAME=keycloak.example.com
EOF

参数说明

  • KEYCLOAK_POSTGRES_IMAGE_TAG=docker.io/library/postgres:16.2: 指定用于 Keycloak 数据库的 PostgreSQL 镜像版本标签。
  • KEYCLOAK_IMAGE_TAG=docker.io/keycloak/keycloak:25.0.4: 指定 Keycloak 服务的镜像版本标签。
  • KEYCLOAK_DB_NAME=keycloakdb: Keycloak 使用的数据库名称。
  • KEYCLOAK_DB_USER=keycloakdbuser: 连接 Keycloak 数据库的用户名。
  • KEYCLOAK_DB_PASSWORD=keycloakdbpass: 连接 Keycloak 数据库的用户密码。
  • KEYCLOAK_ADMIN_USERNAME=keycloakadmin: Keycloak 管理员账户的用户名,用于登录 Keycloak 管理控制台。
  • KEYCLOAK_ADMIN_PASSWORD=keycloakadminpass: Keycloak 管理员账户的密码,用于登录 Keycloak 管理控制台。
  • KEYCLOAK_HOSTNAME=keycloak.example.com: 指定 Keycloak 服务的主机名,用于通过域名访问 Keycloak,替换为您自己的域名。

创建docker-compose文件

cat >/data/keycloak/docker-compose.yaml<<'EOF'
name: 'keyclock'

networks:
  keycloak-network:
    external: true
  traefik-network:
    external: true

volumes:
  keycloak-postgres:

services:
  postgres-keycloak:
    image: ${KEYCLOAK_POSTGRES_IMAGE_TAG}
    volumes:
      - keycloak-postgres:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: ${KEYCLOAK_DB_NAME}
      POSTGRES_USER: ${KEYCLOAK_DB_USER}
      POSTGRES_PASSWORD: ${KEYCLOAK_DB_PASSWORD}
    networks:
      - keycloak-network
    healthcheck:
      test: [ "CMD", "pg_isready", "-q", "-d", "${KEYCLOAK_DB_NAME}", "-U", "${KEYCLOAK_DB_USER}" ]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 60s
    restart: unless-stopped

  keycloak:
    image: ${KEYCLOAK_IMAGE_TAG}
    command: start-dev
    environment:
      KC_DB: postgres
      KC_DB_URL_HOST: postgres-keycloak
      KC_DB_URL_DATABASE: ${KEYCLOAK_DB_NAME}
      KC_DB_USERNAME: ${KEYCLOAK_DB_USER}
      KC_DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD}
      KC_DB_SCHEMA: public
      KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN_USERNAME}
      KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
      KC_HEALTH_ENABLED: 'true'
      KC_HOSTNAME: ${KEYCLOAK_HOSTNAME}
      KC_HTTP_ENABLED: 'true'
      KC_PROXY_HEADERS: 'xforwarded'
      PROXY_ADDRESS_FORWARDING: 'true'
    networks:
      - keycloak-network
      - traefik-network
    healthcheck:
      test:
      - "CMD-SHELL"
      - |
        exec 3<>/dev/tcp/localhost/9000 &&
        echo -e 'GET /health/ready HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' >&3 &&
        cat <&3 | tee /tmp/healthcheck.log | grep -q '200 OK'
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 90s
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.keycloak.rule=Host(`${KEYCLOAK_HOSTNAME}`)"
      - "traefik.http.routers.keycloak.service=keycloak"
      - "traefik.http.routers.keycloak.entrypoints=websecure"
      - "traefik.http.services.keycloak.loadbalancer.server.port=8080"
      - "traefik.http.routers.keycloak.tls=true"
      - "traefik.http.routers.keycloak.tls.certresolver=letsencrypt"
      - "traefik.http.services.keycloak.loadbalancer.passhostheader=true"
      - "traefik.http.routers.keycloak.middlewares=compresstraefik"
      - "traefik.http.middlewares.compresstraefik.compress=true"
      - "traefik.docker.network=traefik-network"
    restart: unless-stopped
    depends_on:
      postgres-keycloak:
        condition: service_healthy
EOF

启动keycloak容器

docker compose up -d

确认容器运行状态

root@ecs01:/data/keycloak# docker compose ps
NAME                           IMAGE                                COMMAND                  SERVICE             CREATED       STATUS                 PORTS
keyclock-keycloak-1            docker.io/keycloak/keycloak:25.0.4   "/opt/keycloak/bin/k…"   keycloak            4 hours ago   Up 4 hours (healthy)   8080/tcp, 8443/tcp, 9000/tcp
keyclock-postgres-keycloak-1   docker.io/library/postgres:16.2      "docker-entrypoint.s…"   postgres-keycloak   4 hours ago   Up 4 hours (healthy)   5432/tcp
root@ecs01:/data/keycloak# 

keycloak配置

浏览器访问keycloak控制台: https://keycloak.example.com,输入keycloak登录账号keycloakadmin及设置的密码。

登录后下拉选择Create realm,新建realm
在这里插入图片描述

指定Realm name名称为outline
在这里插入图片描述
接下来,在“Manage”部分中选择“Clients”,然后单击“Create client”按钮。
在这里插入图片描述
在“Client type”字段中,选择“OpenID Connect”。

在“Client ID”字段中,输入“outline”(小写),然后单击“下一步”按钮。
在这里插入图片描述
接下来,您需要启用“Client authentication”并在“Authentication flow”部分中选择“Standard flow”。应禁用所有其他值。

单击“下一步”按钮。
在这里插入图片描述
设置登录选项

# Root URL
https://outline.example.com/
# Home URL
https://outline.example.com/
# Valid redirect URIs
https://outline.example.com/

请注意,outline.example.com 是我服务的域名。因此,需要指定你自己的域名,该域名指向安装了 Traefik 服务的服务器的 IP 地址,这会将请求重定向到 Outline。

单击“保存”按钮。
在这里插入图片描述

导航到“Credentials”选项卡并复制“Client Secret”字段的内容。
在这里插入图片描述
后续将“客户端密钥”字段的复制内容粘贴到outline .env文件中的OUTLINE_OIDC_CLIENT_SECRET变量中。

Bz8GjPI9E7QqAZcGoQRaktEsW155V5u2

现在让我们创建一个能够使用 Keycloak 登录 Outline 的用户。

在“Manage”部分中选择“Users”,然后单击“Create new user”按钮。
在这里插入图片描述
在下一步中,您需要指定:用户名、电子邮件地址、名字、姓氏和密码。

请注意,如果您提供电子邮件地址,用户不仅可以使用用户名还可以使用电子邮件登录 Outline。

单击“创建”按钮。
在这里插入图片描述
接下来,您需要为新用户设置密码。

转到“Credentials”选项卡,然后单击“Set password”按钮。
在这里插入图片描述
输入强密码并单击“保存”按钮。
在这里插入图片描述
单击“保存密码”按钮确认为用户分配新密码。新密码已成功设置。后续,您可以启动 Outline 及其附带服务,并使用之前创建的用户登录 Outline。

outline部署

创建环境变量文件

cd /data/outline
cat >/data/outline/.env<<EOF
# Outline Variables
OUTLINE_POSTGRES_IMAGE_TAG=postgres:16.2
OUTLINE_IMAGE_TAG=outlinewiki/outline:0.78.0
OUTLINE_REDIS_IMAGE_TAG=redis:7.4.0
OUTLINE_DB_NAME=outlinedb
OUTLINE_DB_USER=outlinedbuser
OUTLINE_DB_PASSWORD=outlinedbpass
OUTLINE_URL=https://outline.example.com
OUTLINE_HOSTNAME=outline.example.com

# MiniIO Variables
OUTLINE_MINIO_USER=bucket.outline
OUTLINE_MINIO_USER_PASSWORD=outlinepass
OUTLINE_MINIO_BUCKET_NAME=outline
OUTLINE_AWS_S3_UPLOAD_BUCKET_URL=https://minio.example.com/outline
OUTLINE_FILE_STORAGE_UPLOAD_MAX_SIZE=104857600000
OUTLINE_FILE_STORAGE_IMPORT_MAX_SIZE=104857600000

# Secret key
# It can be generated with the command:
# openssl rand -hex 32
OUTLINE_SECRET_KEY=00703eaa1fedbb92c903c439feac11e4268c76f6eecc097ba6cc714431b5cb08
# Utils secret
# It can be generated with the command:
# openssl rand -hex 32
OUTLINE_UTILS_SECRET=7eee2571836979c3724f9900a55b1291aa3cdfbc32c42056aacfaaa5b9978649
# Keycloak realm secret
# You need to specify it before starting the Outline container
# It can be found in your realm manage section. Clients/YourClient/Credentials.
OUTLINE_OIDC_CLIENT_SECRET=Bz8GjPI9E7QqAZcGoQRaktEsW155V5u2
# Authentication endpoints
# It can be found in your realm configure section. Realm Settings/General/Endpoints.
OUTLINE_OIDC_AUTH_URI=https://keycloak.example.com/realms/outline/protocol/openid-connect/auth
# It can be found in your realm configure section. Realm Settings/General/Endpoints.
OUTLINE_OIDC_TOKEN_URI=https://keycloak.example.com/realms/outline/protocol/openid-connect/token
# It can be found in your realm configure section. Realm Settings/General/Endpoints.
OUTLINE_OIDC_USERINFO_URI=https://keycloak.example.com/realms/outline/protocol/openid-connect/userinfo
OUTLINE_OIDC_DISPLAY_NAME=Keycloak
OUTLINE_OIDC_USERNAME_CLAIM=email
OUTLINE_OIDC_SCOPES=openid profile email
EOF

outline参数说明:

  • OUTLINE_POSTGRES_IMAGE_TAG=postgres:16.2: 指定用于 Outline 数据库的 PostgreSQL 镜像版本标签。
  • OUTLINE_IMAGE_TAG=outlinewiki/outline:0.78.0: 指定 Outline 应用的镜像版本标签。
  • OUTLINE_REDIS_IMAGE_TAG=redis:7.4.0: 指定用于 Outline 缓存的 Redis 镜像版本标签。
  • OUTLINE_DB_NAME=outlinedb: Outline 使用的数据库名称。
  • OUTLINE_DB_USER=outlinedbuser: 连接 Outline 数据库的用户名。
  • OUTLINE_DB_PASSWORD=outlinedbpass: 连接 Outline 数据库的用户密码。
  • OUTLINE_URL=https://outline.example.com: Outline 应用的公共 URL,用于访问应用。
  • OUTLINE_HOSTNAME=outline.example.com: 指定 Outline 服务的主机名,用于通过域名访问 Outline。

MinIO 相关参数

  • OUTLINE_MINIO_USER=bucket.outline: 用于连接 MinIO 服务的 Outline 用户名,示例格式为bucket.<bucketname>
  • OUTLINE_MINIO_USER_PASSWORD=outlinepass: 用于连接 MinIO 服务的 Outline 用户密码。
  • OUTLINE_MINIO_BUCKET_NAME=outline: MinIO 中用于存储 Outline 文件的存储桶名称。
  • OUTLINE_AWS_S3_UPLOAD_BUCKET_URL=https://minio.example.com/outline: Outline 使用的 MinIO 存储桶的完整 URL。
  • OUTLINE_FILE_STORAGE_UPLOAD_MAX_SIZE=104857600: Outline 允许的最大文件上传大小100M,以字节为单位。
  • OUTLINE_FILE_STORAGE_IMPORT_MAX_SIZE=104857600: Outline 允许的最大导入文件大小100M,以字节为单位。

安全密钥相关参数

  • OUTLINE_SECRET_KEY=: Outline 的应用程序密钥,用于加密数据。
  • OUTLINE_UTILS_SECRET=: 用于实用工具(Utils)的秘密密钥。

Keycloak 相关参数

  • OUTLINE_OIDC_CLIENT_SECRET=: 用于 Keycloak OIDC(OpenID Connect)客户端的秘密密钥。
  • OUTLINE_OIDC_AUTH_URI=: Keycloak 身份验证端点的 URI。
  • OUTLINE_OIDC_TOKEN_URI=: Keycloak 令牌端点的 URI。
  • OUTLINE_OIDC_USERINFO_URI=: Keycloak 用户信息端点的 URI。
  • OUTLINE_OIDC_DISPLAY_NAME=Keycloak: 用于在 Outline 中显示的 OIDC 提供程序名称。
  • OUTLINE_OIDC_USERNAME_CLAIM=email: 指定用于用户名的 OIDC 声明,通常是电子邮件。
  • OUTLINE_OIDC_SCOPES=openid profile email: 指定 OIDC 请求的权限范围,包括基本信息和电子邮件。

创建docker-compose文件

cat >/data/outline/docker-compose.yaml<<'EOF'
name: 'outline'
networks:
  outline-network:
    external: true
  traefik-network:
    external: true

volumes:
  outline-postgres:

services:
  postgres-outline:
    image: ${OUTLINE_POSTGRES_IMAGE_TAG}
    volumes:
      - outline-postgres:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: ${OUTLINE_DB_NAME}
      POSTGRES_USER: ${OUTLINE_DB_USER}
      POSTGRES_PASSWORD: ${OUTLINE_DB_PASSWORD}
    networks:
      - outline-network
    healthcheck:
      test: [ "CMD", "pg_isready", "-q", "-d", "${OUTLINE_DB_NAME}", "-U", "${OUTLINE_DB_USER}" ]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 60s
    restart: unless-stopped

  redis:
    image: ${OUTLINE_REDIS_IMAGE_TAG}
    networks:
      - outline-network
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 60s
    restart: unless-stopped

  outline:
    image: ${OUTLINE_IMAGE_TAG}
    environment:
      DATABASE_URL: postgres://${OUTLINE_DB_USER}:${OUTLINE_DB_PASSWORD}@postgres-outline:5432/${OUTLINE_DB_NAME}?sslmode=disable&connect_timeout=10
      PGSSLMODE: disable
      REDIS_URL: redis://redis:6379
      URL: ${OUTLINE_URL}
      PORT: 3000
      SECRET_KEY: ${OUTLINE_SECRET_KEY}
      UTILS_SECRET: ${OUTLINE_UTILS_SECRET}
      FORCE_HTTPS: 'false'
      ENABLE_UPDATES: 'true'
      AWS_REGION: eu-east-1
      AWS_ACCESS_KEY_ID: ${OUTLINE_MINIO_USER}
      AWS_SECRET_ACCESS_KEY: ${OUTLINE_MINIO_USER_PASSWORD}
      AWS_S3_UPLOAD_BUCKET_URL: ${OUTLINE_AWS_S3_UPLOAD_BUCKET_URL}
      AWS_S3_ACCELERATE_URL: ${OUTLINE_AWS_S3_UPLOAD_BUCKET_URL}
      AWS_S3_UPLOAD_BUCKET_NAME: ${OUTLINE_MINIO_BUCKET_NAME}
      AWS_S3_FORCE_PATH_STYLE: 'false'
      AWS_S3_ACL: private
      FILE_STORAGE_UPLOAD_MAX_SIZE: ${OUTLINE_FILE_STORAGE_UPLOAD_MAX_SIZE}
      FILE_STORAGE_IMPORT_MAX_SIZE: ${OUTLINE_FILE_STORAGE_IMPORT_MAX_SIZE}
      OIDC_CLIENT_ID: outline
      OIDC_CLIENT_SECRET: ${OUTLINE_OIDC_CLIENT_SECRET}
      OIDC_AUTH_URI: ${OUTLINE_OIDC_AUTH_URI}
      OIDC_TOKEN_URI: ${OUTLINE_OIDC_TOKEN_URI}
      OIDC_USERINFO_URI: ${OUTLINE_OIDC_USERINFO_URI}
      OIDC_DISPLAY_NAME: ${OUTLINE_OIDC_DISPLAY_NAME}
      OIDC_USERNAME_CLAIM: ${OUTLINE_OIDC_USERNAME_CLAIM}
      OIDC_SCOPES: ${OUTLINE_OIDC_SCOPES}
    networks:
      - outline-network
      - traefik-network
    healthcheck:
      test: timeout 10s bash -c ':> /dev/tcp/127.0.0.1/3000' || exit 1
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 90s
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.outline.rule=Host(`${OUTLINE_HOSTNAME}`)"
      - "traefik.http.routers.outline.service=outline"
      - "traefik.http.routers.outline.entrypoints=websecure"
      - "traefik.http.services.outline.loadbalancer.server.port=3000"
      - "traefik.http.routers.outline.tls=true"
      - "traefik.http.routers.outline.tls.certresolver=letsencrypt"
      - "traefik.http.services.outline.loadbalancer.passhostheader=true"
      - "traefik.http.routers.outline.middlewares=compresstraefik"
      - "traefik.http.middlewares.compresstraefik.compress=true"
      - "traefik.docker.network=traefik-network"
    restart: unless-stopped
    depends_on:
      postgres-outline:
        condition: service_healthy
      redis:
        condition: service_healthy
EOF

启动outline容器

docker compose up -d

确认容器运行状态

root@ecs01:/data/outline# docker compose ps
NAME                         IMAGE                        COMMAND                  SERVICE            CREATED       STATUS                 PORTS
outline-outline-1            outlinewiki/outline:0.78.0   "docker-entrypoint.s…"   outline            4 hours ago   Up 4 hours (healthy)   3000/tcp
outline-postgres-outline-1   postgres:16.2                "docker-entrypoint.s…"   postgres-outline   4 hours ago   Up 4 hours (healthy)   5432/tcp
outline-redis-1              redis:7.4.0                  "docker-entrypoint.s…"   redis              4 hours ago   Up 4 hours (healthy)   6379/tcp
root@ecs01:/data/outline# 

outline访问

浏览器访问outline控制台: https://outline.example.com,输入outline登录账号admin及设置的密码。

首先会跳转到keycloak进行认证:
在这里插入图片描述
Outline 登录后如下
在这里插入图片描述

新建文档集及文档
在这里插入图片描述
查看对象存储中上传的数据:
在这里插入图片描述

至此,我们在一台云服务器上,通过docker-compose方式完成了outline的部署。

参考:
https://www.heyvaldemar.com/install-outline-and-keycloak-using-docker-compose/
https://github.com/heyvaldemar/outline-keycloak-traefik-letsencrypt-docker-compose

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2112979.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

winndows系统修改cmd用户中文名、系统中文用户名修改为英文用户名的方法

文章目录 一、问题描述二、修改步骤1. 准备&#xff1a;2. 注销&#xff1a;3. 修改&#xff1a;4. 继续修改&#xff1a; 一、问题描述 电脑用户显示中文名&#xff08;我这里已经修改了&#xff09; 二、修改步骤 1. 准备&#xff1a; 我们需要使用 Administrator 登录&am…

OpenGL——画一个填充的三角形

1. vertShader.glsl&#xff08;顶点着色器代码&#xff09;&#xff1a; #version 460void main (void) {if (gl_VertexID 0)gl_Position vec4 (0.25, -0.25, 0.0, 1.0);else if (gl_VertexID 1)gl_Position vec4 (-0.25, -0.25, 0.0, 1.0);elsegl_Position vec4 (0.25,…

[C/C++入门][进制原理]31、求分数序列和

题目来自于信息学奥赛 1078 分析&#xff1a; 这道题看起来比较复杂&#xff0c;实际上只需要通过两个公式&#xff0c;一次性求出分母和分子&#xff0c;然后把这个求出来的数加入到变量和中。甚至都不需要知道总共游哪些数。数组都用不上。循环就能解决。 #include <ios…

快速排序(QuickSort)-归并排序(MergeSort)[java编写]

1. 快速排序 1.1 基本概述 快速排序采用分治思想&#xff0c;即在一个无序的序列中选取一个任意的基准元素pivot&#xff0c;利用pivot 将待排序的序列分成两部分&#xff0c;前面部分元素均小于或等于基准元素&#xff0c;后面部分均大于或等于基准元素&#xff0c;然后采用…

Chapter 10 Stability and Frequency Compensation

Chapter 10 Stability and Frequency Compensation Chapter 8介绍了负反馈, 这一章介绍稳定性, 如果设计不好, 负反馈系统是要发生震荡的. 首先我们学习理解稳定判断标准和条件, 然后学习频率补偿, 介绍适用于不同运放的补偿方式, 同时介绍不同补偿对两级运放slew rate的影响…

2024全新苹果cms影视源码/仿韩剧TV主题模板源码/电影视频在线观看网站源码-自适应 (PC+WAP)

源码简介 2024年最新版的苹果CMS影视源码&#xff0c;仿制了韩剧TV的主题模板&#xff0c;让网站看起来跟韩剧TV一模一样&#xff0c;而且这个源码支持在线观看电影和视频&#xff0c;无论是在电脑&#xff08;PC&#xff09;还是手机&#xff08;WAP&#xff09;上都能完美自…

网络编程之-UDP详解

&#x1f308;个人主页&#xff1a;努力学编程’ ⛅个人推荐&#xff1a; c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构&#xff0c;刷题刻不容缓&#xff1a;点击一起刷题 &#x1f319;心灵鸡汤&#xff1a;总有人要赢&#xff0c;为什么不能是我呢 &#x1f3c0…

2024年 Biomedical Signal Processing and Control 期刊投稿经验最新分享

期刊介绍 《Biomedical Signal Processing and Control 》期刊旨在为临床医学和生物科学中信号和图像的测量和分析研究提供一个跨学科的国际论坛。重点放在处理在临床诊断&#xff0c;患者监测和管理中使用的方法和设备的实际&#xff0c;应用为主导的研究的贡献。 生物医学信…

【大模型基础】P1 N-Gram 模型

目录 N-Gram 概述N-Gram 构建过程TokenN-Gram 实例第1步 构建实验语料库第2步 把句子分成 N 个 “Gram”第3步 计算每个 Bigram 在语料库中的词频第4步 计算出现的概率第5步 生成下一个词第6步&#xff1a;输入前缀&#xff0c;生成连续文本 上述实例完整代码N-Gram 的局限性 N…

一文理解粒子滤波

0. 粒子滤波流程 之前学习记录的文档&#xff0c;这里也拿出来分享一下~ 基本原理&#xff1a;随机选取预测域的 N NN 个点&#xff0c;称为粒子。以此计算出预测值&#xff0c;并算出在测量域的概率&#xff0c;即权重&#xff0c;加权平均就是最优估计。之后按权重比例&…

揭秘帕金森症幕后元凶:是哪些因素悄悄“震颤”了生活?

在这个快节奏的时代&#xff0c;健康成为了我们最宝贵的财富之一。然而&#xff0c;有一种名为“帕金森病”的神秘疾病&#xff0c;正悄悄影响着无数人的生活&#xff0c;让他们的日常充满了“不由自主”的颤抖。今天&#xff0c;就让我们一起揭开帕金森症的神秘面纱&#xff0…

【电路笔记】-同相运算放大器

同相运算放大器 文章目录 同相运算放大器1、概述2、理想的同相运算放大器3、实际同相运算放大器3.1 闭环增益3.2 输出阻抗3.3 输入阻抗4、同相运算放大器示例4.1 缓冲电路4.2 示例5、总结1、概述 施加到运算放大器的电压信号可以提供给其同相输入端 (+) 或反相输入端 (-)。 这…

ansible--role

简介 roles是ansible&#xff0c;playbooks的目录的组织结构&#xff0c;将代码或文件进行模块化&#xff0c;成为roles的文件目录组织结构。 易读&#xff0c;代码可冲哟美好&#xff0c;层次清晰 目录机构 mkdir roles/nginx/{files,handlers,tasks,templates,vars} -ptou…

LLM模型:代码讲解Transformer运行原理

视频讲解、获取源码&#xff1a;LLM模型&#xff1a;代码讲解Transformer运行原理(1)_哔哩哔哩_bilibili 1 训练保存模型文件 2 模型推理 3 推理代码 import torch import tiktoken from wutenglan_model import WutenglanModelimport pyttsx3# 设置设备为CUDA&#xff08;如果…

javaWeb【day04】--(MavenSpringBootWeb入门)

01. Maven课程介绍 1.1 课程安排 学习完前端Web开发技术后&#xff0c;我们即将开始学习后端Web开发技术。做为一名Java开发工程师&#xff0c;后端Web开发技术是我们学习的重点。 1.2 初识Maven 1.2.1 什么是Maven Maven是Apache旗下的一个开源项目&#xff0c;是一款用于…

数据治理:企业数字化转型的关键环节

数据治理&#xff1a;企业数字化转型的关键环节 前言数据治理&#xff1a;企业数字化转型的关键环节 前言 在当今数字化时代&#xff0c;企业的发展与数据紧密相连。数据已成为企业的重要资产&#xff0c;而如何有效地治理数据&#xff0c;使其发挥最大价值&#xff0c;成为企…

Python安装llama库出错“metadata-generation-failed”

Python安装llama库出错“metadata-generation-failed” 1. 安装llama库时出错2. 定位问题1. 去官网下载llama包 2.修改配置文件2.1 解压文件2.2 修改配置文件 3. 本地安装文件 1. 安装llama库时出错 2. 定位问题 根据查到的资料&#xff0c;发现时llama包中的execfile函数已经…

旋翼无人机的应用场景和用途!!!

1. 航拍摄影 全景拍摄&#xff1a;旋翼无人机可以携带摄像装置进行大规模航拍&#xff0c;广泛应用于影视制作、广告拍摄、城市规划、房地产宣传等领域。其独特的视角和高度&#xff0c;能够拍摄到地面难以捕捉的壮丽景色&#xff0c;为观众带来震撼的视觉效果。 测绘与地理信…

USB通信协议基础概念

文章目录 一、什么是USB1. **标准化接口**2. **热插拔**3. **即插即用**4. **电源供给**5. **数据传输速度**6. **连接类型**7. **协议和功能** 二、USB的三个部分1. **USB Host&#xff08;主机&#xff09;**2. **USB Device&#xff08;设备&#xff09;**3. **USB Hub&…

Ubuntu 22.04 make menuconfig 失败原因

先 安装一些配置 linux下使用menuconfig需要安装如下库_menuconfig 安装-CSDN博客 然后 cd 到指定源代码 需要在内核文件目录下编译 Linux 内核源码&#xff08;kernel source&#xff09;路径_--kernel-source-path-CSDN博客 make menuconfig 又报错 说是gcc 12什么什么&…