一次docker镜像的解耦--onlyoffice

栏目: 数据库 · PostgreSQL · 发布时间: 5年前

内容简介:年初的时候就考虑过搭建个在线编辑excel的,之前试过很多这几天又有需求多人同时在线编辑office文件,同事找了个onlyoffice的用docker跑起来了. dockerhub上看了下镜像挺大的而且没有跳转到github上Dockerfile的超链接于是便有了解耦这个镜像的冲动

年初的时候就考虑过搭建个在线编辑excel的,之前试过很多 owncloud,seafile,nextcloud,kodexplorer
基本都是纯网盘或者不免费

这几天又有需求多人同时在线编辑office文件,同事找了个onlyoffice的用 docker 跑起来了. dockerhub上看了下镜像挺大的而且没有跳转到github上Dockerfile的超链接

稍微用docker history看了下发现里面一堆各种数据库都放同一个镜像里,根本没有解耦

一次docker镜像的解耦--onlyoffice

于是便有了解耦这个镜像的冲动

先找官方的例子跑跑看

地址: https://api.onlyoffice.com/editors/demopreview

看了下官方都是js写的,所以选了个Nodejs的demo来跑,另外之前用docker帮过同学搭建过一个nodejs的小程序后台环境,对nodejs项目部署有点经验

选择 Node.js Example

一次docker镜像的解耦--onlyoffice

解压后,修改配置 config/default.jsonm ,siteUrl 为 DocumentServer的地址

一个标准的nodejs项目根目录有package.json文件,里面有模块依赖

npm install 安装模块

node bin/www 即可运行起来

之前帮同学搭建小程序环境(同学是前端,所以用的nodejs写前后端)自己做了个nodejs的镜像,适合测试,每次主进程跑起来之前都会 npm install ,这里用我自己的镜像跑(后期npm的模块可以固化到镜像里,这里仅供快速搭建使用方便)

先简单起来一个试试 documentserver

docker run -d -p 9980:80 onlyoffice/documentserver

然后把修改过后整个demo挂载到镜像的 WORKDIR 跑起来

一次docker镜像的解耦--onlyoffice

一次docker镜像的解耦--onlyoffice

然后在官方的仓库找到了Dockerfile,好吧,不用去看 docker history --no-trunc

https://github.com/ONLYOFFICE/Docker-DocumentServer/blob/master/Dockerfile

看了下Dockerfile整体过程是下面:

添加nodejs的源用于安装nodejs,安装 nodejs,postgres,redis-server,rabbitmq-server,supervisor

开始执行的是一堆目录的 mkdir,chown
然后根据变量值执行,假设此时符合条件进去

ONLYOFFICE_DATA_CONTAINER_HOST=${ONLYOFFICE_DATA_CONTAINER_HOST:-localhost}
...
if [ ${ONLYOFFICE_DATA_CONTAINER_HOST} = "localhost" ]; then

然后执行函数 read_setting
里面是读取文件 /etc/onlyoffice/documentserver/local.json 的值

{
  "services": {
    "CoAuthoring": {
      "sql": {
        "dbHost": "localhost",
        "dbName": "onlyoffice",
        "dbUser": "onlyoffice",
        "dbPass": "onlyoffice"
      },
      "redis": {
        "host": "localhost"
      },
      "token": {
        "enable": {
          "request": {
            "inbox": false,
            "outbox": false
          },
          "browser": false
        },
        "inbox": {
          "header": "Authorization"
        },
        "outbox": {
          "header": "Authorization"
        }
      },
      "secret": {
        "inbox": {
          "string": "secret"
        },
        "outbox": {
          "string": "secret"
        },
        "session": {
          "string": "secret"
        }
      }
    }
  },
  "rabbitmq": {
    "url": "amqp://guest:guest@localhost"
  }
}

如下,变量为空就使用文件里的值

POSTGRESQL_SERVER_HOST=${POSTGRESQL_SERVER_HOST:-$(${JSON} services.CoAuthoring.sql.dbHost)}
POSTGRESQL_SERVER_PORT=${POSTGRESQL_SERVER_PORT:-5432}
POSTGRESQL_SERVER_DB_NAME=${POSTGRESQL_SERVER_DB_NAME:-$(${JSON} services.CoAuthoring.sql.dbName)}
POSTGRESQL_SERVER_USER=${POSTGRESQL_SERVER_USER:-$(${JSON} services.CoAuthoring.sql.dbUser)}
POSTGRESQL_SERVER_PASS=${POSTGRESQL_SERVER_PASS:-$(${JSON} services.CoAuthoring.sql.dbPass)}

RABBITMQ_SERVER_URL=${RABBITMQ_SERVER_URL:-$(${JSON} rabbitmq.url)}
parse_rabbitmq_url

REDIS_SERVER_HOST=${REDIS_SERVER_HOST:-$(${JSON} services.CoAuthoring.redis.host)}
REDIS_SERVER_PORT=${REDIS_SERVER_PORT:-6379}

DS_LOG_LEVEL=${DS_LOG_LEVEL:-$(${JSON_LOG} levels.nodeJS)}

parse_rabbitmq_url函数从变量 local.json 里的 rabbitmq.url 值分离成下面

RABBITMQ_SERVER_HOST=$host
RABBITMQ_SERVER_USER=$user
RABBITMQ_SERVER_PASS=$pass
RABBITMQ_SERVER_PORT=$port

也就是把 amqp://guest:guest@localhost 分离成

amqp://${用户名}:${密码}@${host}:${port:=5672}

函数 update_log_settings 修改 $DS_LOG_LEVEL ,缺省值为文件的 /etc/onlyoffice/documentserver/log4js/production.jsonlevels.nodeJS

{
  "appenders": [
    {
      "type": "console",
      "layout": {
        "type": "pattern",
        "pattern": "[%d] [%p] %c - %.10000m"
      }
    }
  ],
  "replaceConsole": "true",
  "levels": {
    "nodeJS": "WARN"
  }
}

然后执行函数 update_jwt_settings 满足条件就

if [ "${JWT_ENABLED}" == "true" ]

JWT_ENABLED 缺省为false

然后改local.json里的对应值,自行看脚本,这里不啰嗦,而且我没用jwt

接下来pgsql部分,数据存放变量为下

PG_ROOT=/var/lib/postgresql
PG_VERSION=9.5
PG_NAME=main
PGDATA=${PG_ROOT}/${PG_VERSION}/${PG_NAME}

POSTGRESQL_SERVER_HOST 缺省用local.json文件里的 .services.CoAuthoring.sql.dbhost

if [ ${POSTGRESQL_SERVER_HOST} != "localhost" ]; then
  update_postgresql_settings
  waiting_for_postgresql
  create_postgresql_tbl

如果 POSTGRESQL_SERVER_HOST 不是localhost就用local.json文件里的 .services.CoAuthoring.sql.dbhost
此时是使用外部的pgsql,有等待端口的函数

waiting_for_connection(){
  until nc -z -w 3 "$1" "$2"; do
    >&2 echo "Waiting for connection to the $1 host on port $2"
    sleep 1
  done
}

外部pgsql数据库就绪后就执行db初始化的sql,sql文件位置 /var/www/onlyoffice/documentserver/server/schema/postgresql/createdb.sql

--
-- Create schema onlyoffice
--

-- CREATE DATABASE onlyoffice ENCODING = 'UTF8' CONNECTION LIMIT = -1;

-- ----------------------------
-- Table structure for doc_changes
-- ----------------------------
CREATE TABLE IF NOT EXISTS "public"."doc_changes" (
"id" varchar(255) COLLATE "default" NOT NULL,
"change_id" int4 NOT NULL,
"user_id" varchar(255) COLLATE "default" NOT NULL,
"user_id_original" varchar(255) COLLATE "default" NOT NULL,
"user_name" varchar(255) COLLATE "default" NOT NULL,
"change_data" text COLLATE "default" NOT NULL,
"change_date" timestamp without time zone NOT NULL,
PRIMARY KEY ("id", "change_id")
)
WITH (OIDS=FALSE);

-- ----------------------------
-- Table structure for task_result
-- ----------------------------
CREATE TABLE IF NOT EXISTS "public"."task_result" (
"id" varchar(255) COLLATE "default" NOT NULL,
"status" int2 NOT NULL,
"status_info" int4 NOT NULL,
"last_open_date" timestamp without time zone NOT NULL,
"user_index" int4 NOT NULL DEFAULT 1,
"change_id" int4 NOT NULL DEFAULT 0,
"callback" text COLLATE "default" NOT NULL,
"baseurl" text COLLATE "default" NOT NULL,
PRIMARY KEY ("id")
)
WITH (OIDS=FALSE);

CREATE OR REPLACE FUNCTION merge_db(_id varchar(255), _status int2, _status_info int4, _last_open_date timestamp without time zone, _user_index int4, _change_id int4, _callback text, _baseurl text, OUT isupdate char(5), OUT userindex int4) AS
$$
DECLARE
	t_var "public"."task_result"."user_index"%TYPE;
BEGIN
	LOOP
		-- first try to update the key
		-- note that "a" must be unique
		UPDATE "public"."task_result" SET last_open_date=_last_open_date, user_index=user_index+1 WHERE id = _id RETURNING user_index into userindex;
		IF found THEN
			isupdate := 'true';
			RETURN;
		END IF;
		-- not there, so try to insert the key
		-- if someone else inserts the same key concurrently,
		-- we could get a unique-key failure
		BEGIN
			INSERT INTO "public"."task_result"(id, status, status_info, last_open_date, user_index, change_id, callback, baseurl) VALUES(_id, _status, _status_info, _last_open_date, _user_index, _change_id, _callback, _baseurl) RETURNING user_index into userindex;
			isupdate := 'false';
			RETURN;
		EXCEPTION WHEN unique_violation THEN
			-- do nothing, and loop to try the UPDATE again
		END;
	END LOOP;
END;
$$
LANGUAGE plpgsql;

如果此时使用的是容器内的pgsql则

chown -R postgres:postgres ${PG_ROOT}
chmod -R 700 ${PG_ROOT}

不存在目录 PGDATA

local pg_conf_dir=/etc/postgresql/${PG_VERSION}/${PG_NAME}
local postgresql_conf=$pg_conf_dir/postgresql.conf
local hba_conf=$pg_conf_dir/pg_hba.conf

mv $postgresql_conf $postgresql_conf.backup
mv $hba_conf $hba_conf.backup

pg_createcluster ${PG_VERSION} ${PG_NAME}
PG_NEW_CLUSTER=true

rabbitmq一样, RABBITMQ_SERVER_HOST 值不是localhost就使用外部的,是localhost此时就 rm -rf /var/run/rabbitmq 来保证startup after container kill

redis的host不是localhost就使用

${JSON} -I -e "this.services.CoAuthoring.redis.host = '${REDIS_SERVER_HOST}'"
${JSON} -I -e "this.services.CoAuthoring.redis.port = '${REDIS_SERVER_PORT}'"

上面对比文件的json对不上,怀疑此处写错了.而且 redis 没设置密码,解耦的话应该改下onlyoffice的客户端连接参数加上密码

ONLYOFFICE_DATA_CONTAINER_HOST 上面都是符合条件就是localhost, 此时进else的话就是执行到行316行函数 waiting_for_datacontainer just wait for remote data

此时执行函数 read_setting

看了下默认的80端口是nginx占据的,此处应该是webserver

上面如果是localhost就会在容器里启动 pgsql,rabbitmq,redis

然后下面这段代码

if [ ${PG_NEW_CLUSTER} = "true" ]; then
  create_postgresql_db
  create_postgresql_tbl
fi

如果PG是初始化的(也就是前面的一开始不存在目录 PGDATA )

create_postgresql_db(){
  sudo -u postgres psql -c "CREATE DATABASE onlyoffice;"
  sudo -u postgres psql -c "CREATE USER onlyoffice WITH password 'onlyoffice';"
  sudo -u postgres psql -c "GRANT ALL privileges ON DATABASE onlyoffice TO onlyoffice;"
}

create_postgresql_tbl 就是上面的sql /var/www/onlyoffice/documentserver/server/schema/postgresql/createdb.sql 初始化pgsql

然后下面这段

if [ ${ONLYOFFICE_DATA_CONTAINER} != "true" ]; then
  waiting_for_postgresql
  waiting_for_rabbitmq
  waiting_for_redis

  update_nginx_settings

  update_supervisor_settings
  service supervisor start
  
  # start cron to enable log rotating
  service cron start
fi

这里的 ONLYOFFICE_DATA_CONTAINER 值由于没有接触过onlyoffice不知道这个值干啥的

waiting开头的都是等服务端口起来

update_nginx_settings 看了下是修改nginx的配置文件(/etc/nginx/nginx.conf),否则改为缺省,下面只说缺省修改

  • worker_processes 开头的值修改环境变量,缺省为1
  • worker_connections 缺省改为 $(ulimit -n)
  • access_log.* 改为 access_log off; (此处关掉access.log)
  • 如果存在文件 SSL_CERTIFICATE_PATH (缺省为 /var/www/onlyoffice/Data/certs/onlyoffice.crt )和文件 SSL_KEY_PATH (缺省为 /var/www/onlyoffice/Data/certs/onlyoffice.key )
  • 接上: 就复制文件 /etc/onlyoffice/documentserver/nginx/onlyoffice-documentserver-ssl.conf.template$NGINX_ONLYOFFICE_CONF (缺省为 /etc/onlyoffice/documentserver/nginx/onlyoffice-documentserver.conf )
  • 这里后面注意下,因为上一步是复制了文件的,后面可以直接对着template文件看
  • 接上面的ssl,修改文件 $NGINX_ONLYOFFICE_CONF$SSL_CERTIFICATE_PATH
  • 同上修改
  • 开启http2,即替换 443 ssl443 ssl http2
  • 如果 $SSL_DHPARAM_PATH (缺省 /var/www/onlyoffice/Data/certs/dhparam.pem )可读把行 # ssl_dhparam /etc/ssl/certs/dhparam.pem; 取消注释,不可读就删除这行
  • 修改包含”ssl_verify_client”行后面的值为 ${SSL_VERIFY_CLIENT}
  • ${CA_CERTIFICATES_PATH} 存在在行”ssl_verify_client”下一行插入 ssl_client_certificate ${CA_CERTIFICATES_PATH}
  • 如果 $ONLYOFFICE_HTTPS_HSTS_ENABLED 为true修改 max-age=31536000 的值改为 $ONLYOFFICE_HTTPS_HSTS_MAXAGE ,不为true则删除包含max-age的行
  • 以上逻辑都是第四条的存在俩文件,如果不存在俩文件则软连接 ${NGINX_ONLYOFFICE_PATH}/onlyoffice-documentserver.conf.template${NGINX_ONLYOFFICE_PATH}/onlyoffice-documentserver.conf ,也就是此时不适用ssl
  • 下面不包含在上面的存在文件代码块里
  • 存在文件 $NGINX_ONLYOFFICE_EXAMPLE_CONF 修改它里面的”linux”改成”docker”
  • update_supervisor_settings 就是把supervisor的配置文件复制到它默认工作目录去
  • 然后启动supervisor和cron
  • 下面是349行后面全局执行的逻辑
  • 启动nginx,这里想不通为啥跑个nginx,后面看看能看懂原因不
  • 最后的 documentserver-generate-allfonts.shdocumentserver-static-gzip.sh 一个是字体一个是压缩备份

整体思路有了,但是发现documentserver似乎好几个组件一起被supervisor跑的

root@918cd6b41d37:/etc/supervisor/conf.d# ll
total 0
drwxr-xr-x 1 root root 279 Oct 26 15:16 ./
drwxr-xr-x 1 root root  30 Oct 26 08:31 ../
lrwxrwxrwx 1 root root  73 Oct 26 15:09 onlyoffice-documentserver.conf -> ../../onlyoffice/documentserver/supervisor/onlyoffice-documentserver.conf
lrwxrwxrwx 1 root root  83 Oct 26 15:09 onlyoffice-documentserver-converter.conf -> ../../onlyoffice/documentserver/supervisor/onlyoffice-documentserver-converter.conf
lrwxrwxrwx 1 root root  84 Oct 26 15:09 onlyoffice-documentserver-docservice.conf -> ../../onlyoffice/documentserver/supervisor/onlyoffice-documentserver-docservice.conf
lrwxrwxrwx 1 root root  76 Oct 26 15:09 onlyoffice-documentserver-gc.conf -> ../../onlyoffice/documentserver/supervisor/onlyoffice-documentserver-gc.conf
lrwxrwxrwx 1 root root  81 Oct 26 15:09 onlyoffice-documentserver-metrics.conf -> ../../onlyoffice/documentserver/supervisor/onlyoffice-documentserver-metrics.conf
lrwxrwxrwx 1 root root  86 Oct 26 15:09 onlyoffice-documentserver-spellchecker.conf -> ../../onlyoffice/documentserver/supervisor/onlyoffice-documentserver-spellchecker.conf

所以entrypoint里启动supervisor的时候会启动onlyoffice

镜像里依赖安装太多了,然后找到了非docker安装的文档稍微清晰了些

https://helpcenter.onlyoffice.com/server/linux/document/linux-installation-centos.aspx?_ga=2.211658390.2064741635.1541596271-1982326324.1541482842

https://helpcenter.onlyoffice.com/server/linux/document/index.aspx

安装了 onlyoffice-documentserver 后发现大体文件一样,解包rpm后更直观

yum install onlyoffice-documentserver

整体思路有了,documentserver的源码都放一起,里面几个组建都是supervisor跑

源码是js的,所以这几个组建分离解耦的话必须在nodejs作为基础镜像(so依赖啥的不知道解决起来麻烦不)

然后一些数据库啥的可以直接各自的官方镜像稍微挂载初始化 sql 啥的

由于对于nodejs不熟悉,同学上班也忙,无法帮我拆分项目,项目结构也不熟悉

一次docker镜像的解耦--onlyoffice

目前是打算是把nginx,supervisor(来管理这些组件)放同一个镜像算了,感觉documentserver拆分得太散没必要

看了官方文档的环境要求介绍

Software requirements
For Debian, Ubuntu and derivatives
OS 64-bit Debian, Ubuntu or other compatible distribution with kernel version 3.13 or later
Additional Requirements
PostgreSQL: version 9.1 or later
NGINX: version 1.3.13 or later
Node.js: version 8.12.0 or later
libstdc++6: version 4.8.4 or later
Redis
RabbitMQ
For RHEL, CentOS and derivatives
OS RHEL 7 or CentOS 7
Additional Requirements
PostgreSQL: version 9.1 or later
NGINX: version 1.3.13 or later
Node.js: version 8.12.0 or later
Redis
RabbitMQ

发现官方源码clone下来居然1.7G,想了下还是ubuntu作为基础镜像,像官方那样去包管理去安装算了

一次docker镜像的解耦--onlyoffice

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

游戏运营:高手进阶之路

游戏运营:高手进阶之路

饭大官人 / 电子工业出版社 / 2018-1-1 / 79.00元

《游戏运营:高手进阶之路》是一本系统的、成体系的、注重运营效能、强化系统思维、提升专业认知的书籍。《游戏运营:高手进阶之路》几乎完整覆盖了一个游戏运营人员日常工作中的方方面面,并从工作中具体的业务场景出发,归纳整理出各种解决问题的方法论。《游戏运营:高手进阶之路》为广大游戏从业者建立了完整的知识技能成长体系,包含两大岗位基本功—内容输出和协作推进,四大职业技能—活动策划、版本管理、用户运营、数据分......一起来看看 《游戏运营:高手进阶之路》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具