用Raspberry Pi 4的Docker将OpenProject运行起来
似乎需要更加努力才能支持建筑业界的功能。
※如COLLADA2GLTF或IFCconvert之类的工具。想要使用的人请继续努力吧…虽然构建是成功的。不过太长就不写了。
背景
最近我尝试在Redmine上使用GTD,已经运营了大约两周。然而,我发现为了让它更易用,需要安装近10个插件;而且有很多地方不够灵活。简单搜索后,我发现OpenProject在默认情况下拥有我需要的功能。因此,我决定尝试在官方不支持的arm64架构上使用Docker来运行OpenProject。结果基本上成功了,所以我决定为了全世界的某个人而发布这篇文章。
环境建设
大致的构建方法如下:
-
- 公式の Dockerfile を元に arm64 で動くように変更を加える
-
- All in One コンテナではなく、docker-compose を使用するバージョンの arm64 版を目指す
- https を有効にするために letsencrypt を利用する自作の proxy を立てる
首先,我们的目标是使All in One容器运行。
克隆公式的GitHub存储库
git clone https://github.com/opf/openproject.git
# 真面目な人はこの後、タグをチェックアウトしてね。私は面倒なのでデフォルトブランチで作業します。
修改docker/prod/Dockerfile
将gosu更改为arm64版本使用。
#克隆并修改所下载的内容(包括中间的COPY . .)
#如果需要重新开始,也可以在主机上下载,但容易忘记重新执行。
FROM ruby:2.7.2-buster
MAINTAINER operations@openproject.com
# Allow platform-specific additions. Valid values are: on-prem,saas,bahn
ARG PLATFORM=on-prem
# Use OAuth token in case private gems need to be fetched
ARG GITHUB_OAUTH_TOKEN
ARG DEBIAN_FRONTEND=noninteractive
ARG PGLOADER_BINARY_DOWNLOAD_URL=https://openproject-docker-public.s3-eu-west-1.amazonaws.com/pgloader/bin/pgloader-ccl
ENV NODE_VERSION="12.18.3"
ENV BUNDLER_VERSION="2.1.4"
ENV BUNDLE_PATH__SYSTEM=false
ENV APP_USER=app
ENV APP_PATH=/app
ENV APP_DATA_PATH=/var/openproject/assets
ENV APP_DATA_PATH_LEGACY=/var/db/openproject
ENV PGDATA=/var/openproject/pgdata
ENV PGDATA_LEGACY=/var/lib/postgresql/9.6/main
ENV DATABASE_URL=postgres://openproject:openproject@127.0.0.1/openproject
ENV RAILS_ENV=production
ENV RAILS_CACHE_STORE=memcache
ENV RAILS_GROUPS=production
ENV RAILS_LOG_TO_STDOUT=1
ENV RAILS_SERVE_STATIC_FILES=1
ENV OPENPROJECT_INSTALLATION__TYPE=docker
# Valid values are: standard,bim
ENV OPENPROJECT_EDITION=standard
ENV NEW_RELIC_AGENT_ENABLED=false
ENV ATTACHMENTS_STORAGE_PATH=$APP_DATA_PATH/files
# Set a default key base, ensure to provide a secure value in production environments!
ENV SECRET_KEY_BASE=OVERWRITE_ME
RUN curl ${PGLOADER_BINARY_DOWNLOAD_URL} > /usr/local/bin/pgloader-ccl && chmod +x /usr/local/bin/pgloader-ccl
WORKDIR $APP_PATH
COPY docker/prod/setup ./docker/prod/setup
RUN ./docker/prod/setup/preinstall.sh
COPY Gemfile ./Gemfile
COPY Gemfile.* ./
COPY modules ./modules
COPY vendor ./vendor
# some gemspec files of plugins require files in there, notably OpenProject::Version
COPY lib ./lib
RUN bundle install --quiet --deployment --path vendor/bundle --no-cache \
--with="$RAILS_GROUPS" --without="test development" --jobs=8 --retry=3 && \
rm -rf vendor/bundle/ruby/*/cache && rm -rf vendor/bundle/ruby/*/gems/*/spec && rm -rf vendor/bundle/ruby/*/gems/*/test
# Finally, copy over the whole thing
COPY . .
# Replace gosu with gosu-arm64
RUN wget -O ./docker/prod/gosu https://github.com/tianon/gosu/releases/download/1.12/gosu-arm64
RUN ./docker/prod/setup/postinstall.sh
# Expose ports for apache and postgres
EXPOSE 8080 5432
# Expose the postgres data directory and OpenProject data directory as volumes
VOLUME ["$PGDATA", "$APP_DATA_PATH"]
# Set a custom entrypoint to allow for privilege dropping and one-off commands
ENTRYPOINT ["./docker/prod/entrypoint.sh"]
# Set default command to launch the all-in-one configuration supervised by supervisord
CMD ["./docker/prod/supervisord"]
修改docker/prod/setup/preinstall-common.sh
将指定x64版本的二进制文件的部分更改为使用arm64版本。
#!/bin/bash
set -e
set -o pipefail
# install node + npm
curl -s https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-arm64.tar.gz | tar xzf - -C /usr/local --strip-components=1
wget --quiet -O- https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
echo "deb http://apt.postgresql.org/pub/repos/apt buster-pgdg main" > /etc/apt/sources.list.d/pgdg.list
apt-get update -qq
apt-get install -y \
apt-transport-https \
pandoc \
poppler-utils \
unrtf \
tesseract-ocr \
catdoc \
postgresql-9.6 \
postgresql-client-9.6 \
imagemagick
rm -rf "$PGDATA_LEGACY"
# Specifics for BIM edition
curl -SL -o dotnet.tar.gz https://dotnetcli.blob.core.windows.net/dotnet/Runtime/master/dotnet-runtime-latest-linux-arm64.tar.gz
mkdir -p /usr/share/dotnet
tar -zxf dotnet.tar.gz -C /usr/share/dotnet
ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet
tmpdir=$(mktemp -d)
cd $tmpdir
# Install XKT converter
npm install @xeokit/xeokit-gltf-to-xkt@0.0.3 -g
# Install COLLADA2GLTF
wget --quiet https://github.com/KhronosGroup/COLLADA2GLTF/releases/download/v2.1.5/COLLADA2GLTF-v2.1.5-linux.zip
unzip -q COLLADA2GLTF-v2.1.5-linux.zip
mv COLLADA2GLTF-bin "/usr/local/bin/COLLADA2GLTF"
# IFCconvert
wget --quiet https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.6.0-9bcd932-linux64.zip
unzip -q IfcConvert-v0.6.0-9bcd932-linux64.zip
mv IfcConvert "/usr/local/bin/IfcConvert"
wget --quiet https://github.com/bimspot/xeokit-metadata/releases/download/1.0.0/xeokit-metadata-linux-arm.tar.gz
tar -zxvf xeokit-metadata-linux-arm.tar.gz
chmod +x xeokit-metadata-linux-arm/xeokit-metadata
cp -r xeokit-metadata-linux-arm/ "/usr/lib/xeokit-metadata"
ln -s /usr/lib/xeokit-metadata/xeokit-metadata /usr/local/bin/xeokit-metadata
cd /
rm -rf $tmpdir
gem install bundler --version "$BUNDLER_VERSION" --no-document
useradd -d /home/$APP_USER -m $APP_USER
建设(大约需要20分钟)
docker build -t openproject/community:11-arm64 -f docker/prod/Dockerfile ./
进行烟雾测试
docker run --rm -it -p 8080:80 -e SECRET_KEY_BASE=secret openproject/community:11-arm64
在使用docker-compose运行
获取公式的 docker-compose.yml
git clone https://github.com/opf/openproject-deploy --depth=1 --branch=stable/11 openproject
cd openproject/compose
nano docker-compose.yml
修改docker-compose.yml文件
-
- コンテナネーム app のイメージを自作のイメージに変更する
volumes のホスト側のマウントポイントをカレントディレクトリにする
version: "3.7"
networks:
frontend:
backend:
volumes:
pgdata:
opdata:
x-op-restart-policy: &restart_policy
restart: unless-stopped
x-op-image: &image
image: openproject/community:11-arm64
x-op-app: &app
<<: *image
<<: *restart_policy
environment:
RAILS_CACHE_STORE: "memcache"
OPENPROJECT_CACHE__MEMCACHE__SERVER: "cache:11211"
OPENPROJECT_RAILS__RELATIVE__URL__ROOT: "${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}"
DATABASE_URL: "postgres://postgres:p4ssw0rd@db/openproject"
USE_PUMA: "true"
# set to true to enable the email receiving feature. See ./docker/cron for more options
IMAP_ENABLED: "${IMAP_ENABLED:-false}"
volumes:
- "./opdata:/var/openproject/assets"
services:
db:
image: postgres:10
<<: *restart_policy
stop_grace_period: "3s"
volumes:
- "./pgdata:/var/lib/postgresql/data"
environment:
POSTGRES_PASSWORD: p4ssw0rd
POSTGRES_DB: openproject
networks:
- backend
cache:
image: memcached
<<: *restart_policy
networks:
- backend
proxy:
<<: *image
<<: *restart_policy
command: "./docker/prod/proxy"
ports:
- "${PORT:-8080}:80"
environment:
APP_HOST: web
OPENPROJECT_RAILS__RELATIVE__URL__ROOT: "${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}"
depends_on:
- web
networks:
- frontend
web:
<<: *app
command: "./docker/prod/web"
networks:
- frontend
- backend
depends_on:
- db
- cache
- seeder
worker:
<<: *app
command: "./docker/prod/worker"
networks:
- backend
depends_on:
- db
- cache
- seeder
cron:
<<: *app
command: "./docker/prod/cron"
networks:
- backend
depends_on:
- db
- cache
- seeder
seeder:
<<: *app
command: "./docker/prod/seeder"
restart: on-failure
networks:
- backend
执行(烟雾)测试
docker-compose up
启用HTTPS
目录结构
compose/
├── docker-compose.yml #変更する
└── proxy #作成する
├── Dockerfile #作成する
└── default.conf.template #作成する
将代理更改为自制的。
FROM nginx:latest
ARG CERTBOT_EMAIL=default@default.com
ARG DOMAIN_LIST
# Expose ports.
EXPOSE 80
EXPOSE 443
RUN apt-get update \
&& apt-get install -y cron certbot \
&& certbot certonly --dry-run --standalone --agree-tos -m "${CERTBOT_EMAIL}" -n -d ${DOMAIN_LIST} \
&& certbot certonly --standalone --agree-tos -m "${CERTBOT_EMAIL}" -n -d ${DOMAIN_LIST} \
&& rm -rf /var/lib/apt/lists/* \
&& echo "@monthly /usr/bin/certbot renew --nginx >> /var/log/cron.log 2>&1" >/etc/cron.d/certbot-renew \
&& crontab /etc/cron.d/certbot-renew
VOLUME /etc/letsencrypt
CMD [ "sh", "-c", "cron && ./docker-entrypoint.sh nginx -g 'daemon off;'" ]
修改docker-compose.yml文件
version: "3.7"
networks:
frontend:
backend:
volumes:
pgdata:
opdata:
x-op-restart-policy: &restart_policy
restart: unless-stopped
x-op-image: &image
image: openproject/community:11-arm64
x-op-app: &app
<<: *image
<<: *restart_policy
container_name: app
environment:
RAILS_CACHE_STORE: "memcache"
OPENPROJECT_CACHE__MEMCACHE__SERVER: "cache:11211"
OPENPROJECT_RAILS__RELATIVE__URL__ROOT: "${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}"
DATABASE_URL: "postgres://postgres:p4ssw0rd@db/openproject"
USE_PUMA: "true"
# set to true to enable the email receiving feature. See ./docker/cron for more options
IMAP_ENABLED: "${IMAP_ENABLED:-false}"
volumes:
- "./opdata:/var/openproject/assets"
services:
db:
container_name: db
image: postgres:10
<<: *restart_policy
stop_grace_period: "3s"
volumes:
- "./pgdata:/var/lib/postgresql/data"
environment:
POSTGRES_PASSWORD: p4ssw0rd
POSTGRES_DB: openproject
networks:
- backend
cache:
container_name: cache
image: memcached
<<: *restart_policy
networks:
- backend
# proxy:
# <<: *image
# <<: *restart_policy
# command: "./docker/prod/proxy"
# ports:
# - "${PORT:-8080}:80"
# environment:
# APP_HOST: web
# OPENPROJECT_RAILS__RELATIVE__URL__ROOT: "${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}"
proxy:
<<: *restart_policy
container_name: proxy
build:
context: ./proxy
network: host
args:
- CERTBOT_EMAIL=your-email@mail.com #replace with your own email
- DOMAIN_LIST=your.hostname.com #replace with your own domains
ports:
- "80:80"
- "443:443"
volumes:
- ./proxy/default.conf.template:/etc/nginx/templates/default.conf.template
environment:
MY_DOMAIN_NAME: your.hostname.com #replace with your own domains
depends_on:
- web
networks:
- frontend
web:
<<: *app
container_name: web
command: "./docker/prod/web"
networks:
- frontend
- backend
depends_on:
- db
- cache
- seeder
worker:
<<: *app
container_name: worker
command: "./docker/prod/worker"
networks:
- backend
depends_on:
- db
- cache
- seeder
cron:
<<: *app
container_name: cron
command: "./docker/prod/cron"
networks:
- backend
depends_on:
- db
- cache
- seeder
seeder:
<<: *app
container_name: seeder
command: "./docker/prod/seeder"
restart: on-failure
networks:
- backend
修改proxy/default.conf.template。
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/letsencrypt/live/${MY_DOMAIN_NAME}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${MY_DOMAIN_NAME}/privkey.pem;
location / {
proxy_pass http://web:8080/;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect http:// https://;
}
# --- For CertBot ---
location ^~ /.well-known/acme-challenge/ {
root /usr/share/nginx/html/;
}
location = /.well-known/acme-challenge/ {
return 404;
}
}
疏通(煙熏)測試
docker-compose up