安装必要的依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# 安装 podman $ sudo apt install podman # 安装 git $ sudo apt install git # 创建一个低权限用户,尽量不要使用root用户,身份操作podman,降低安全风险 $ sudo adduser podman # 允许用户下的容器在系统启动的时候启动服务 $ sudo loginctl enable-linger podman # 切换到刚刚创建的低权限用户 ,注意,必须使用 su - user 的方式切换 # 如果使用 su user 切换会导致环境变量被带到新用户,导致执行报错 # ERRO[0000] XDG_RUNTIME_DIR directory "/run/user/1000" is not owned by the current user $ su - podman # 准备本地目录映射 $ mkdir ~/.dockers $ mkdir ~/.dockers/opengrok # 准备已经处理过的源代码,源代码需要 src、etc、data 三个目录,src存储源代码,其他目录保持空即可 # 参考 https://www.mobibrw.com/2019/19162 # 更详细的处理参考官方文档即可,后续我们以 Android 4.2.2 的源代码为例子 # Android 4.2.2 源代码存放在 ~/.dockers/opengrok/Android_4.2.2/src $ mkdir ~/.dockers/opengrok/Android_4.2.2/src $ mkdir ~/.dockers/opengrok/Android_4.2.2/etc $ mkdir ~/.dockers/opengrok/Android_4.2.2/data # 手工拉去部分镜像,或者可以在 /etc/containers/registries.conf 配置镜像服务器,可省略前面的服务器 docker.io $ podman pull docker.io/library/tomcat:10-jdk17 $ podman pull docker.io/library/tomcat:10.1-jdk17 |
官方镜像会在报错的时候暴露 Tomcat 10 版本号,错误堆栈,构成安全隐患,我们需要通过构建自定义镜像解决此问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# 目前最新代码 commit ad9658443340a6dae425d94ab7cb0cc9d74fb37f $ git clone https://github.com/oracle/opengrok.git $ cd opengrok # 设置 maven 国内代理,否则下载速度太慢了 $ find . -type f -exec grep -l "repo.maven" {} \; | xargs sed -i "s/repo.maven.apache.org\/maven2\//mirrors.cloud.tencent.com\/nexus\/repository\/maven-public\//" # 设置 Maven Wrapper 国内源 $ sed -i "s/repo.maven.apache.org\/maven2\//mirrors.cloud.tencent.com\/nexus\/repository\/maven-public\//" .mvn/wrapper/maven-wrapper.properties # 代码中使用的 linux 系统镜像版本,我们需要明确告知 podman 从 docker.io 获取 $ sed -i "s/ubuntu:jammy/docker.io\/ubuntu:jammy/g" Dockerfile # 代码中使用的 Tomcat 镜像版本,不能通过 docker.io 获取到,我们直接使用通用 Tomcat 10 版本 $ sed -i "s/tomcat:10.1.19-jdk17/docker.io\/library\/tomcat:10.1-jdk17/g" Dockerfile |
内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved. # Portions Copyright (c) 2020, Chris Fraire <cfraire@me.com>. FROM docker.io/ubuntu:jammy AS build # hadolint ignore=DL3008 RUN apt-get update && apt-get install --no-install-recommends -y openjdk-17-jdk python3 python3-venv && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* # Create a first layer to cache the "Maven World" in the local repository. # Incremental docker builds will always resume after that, unless you update the pom WORKDIR /mvn COPY pom.xml /mvn/ COPY mvnw /mvn/ COPY .mvn /mvn/.mvn COPY opengrok-indexer/pom.xml /mvn/opengrok-indexer/ COPY opengrok-web/pom.xml /mvn/opengrok-web/ COPY plugins/pom.xml /mvn/plugins/ COPY suggester/pom.xml /mvn/suggester/ # distribution and tools do not have dependencies to cache RUN sed -i 's:<module>distribution</module>::g' /mvn/pom.xml && \ sed -i 's:<module>tools</module>::g' /mvn/pom.xml && \ mkdir -p /mvn/opengrok-indexer/target/jflex-sources && \ mkdir -p /mvn/opengrok-web/src/main/webapp/js && \ mkdir -p /mvn/opengrok-web/src/main/webapp/WEB-INF/ && \ touch /mvn/opengrok-web/src/main/webapp/WEB-INF/web.xml # dummy build to cache the dependencies RUN ./mvnw -DskipTests -Dcheckstyle.skip -Dmaven.antrun.skip package # build the project COPY ./ /opengrok-source WORKDIR /opengrok-source RUN /mvn/mvnw -DskipTests=true -Dmaven.javadoc.skip=true -B -V package # hadolint ignore=SC2012,DL4006 RUN cp `ls -t distribution/target/*.tar.gz | head -1` /opengrok.tar.gz # Store the version in a file so that the tools can report it. RUN /mvn/mvnw help:evaluate -Dexpression=project.version -q -DforceStdout > /mvn/VERSION FROM docker.io/library/tomcat:10.1-jdk17 LABEL maintainer="https://github.com/oracle/opengrok" # Add Perforce apt source. # hadolint ignore=DL3008,DL3009 RUN apt-get update && \ apt-get install --no-install-recommends -y gnupg2 SHELL ["/bin/bash", "-o", "pipefail", "-c"] # hadolint ignore=DL3059 RUN curl -sS https://package.perforce.com/perforce.pubkey | gpg --dearmor > /etc/apt/trusted.gpg.d/perforce.gpg # hadolint ignore=DL3059 RUN echo 'deb https://package.perforce.com/apt/ubuntu jammy release' > /etc/apt/sources.list.d/perforce.list # install dependencies and Python tools # hadolint ignore=DL3008,DL3009 RUN apt-get update && \ apt-get install --no-install-recommends -y git subversion mercurial cvs cssc bzr rcs rcs-blame \ unzip python3 python3-pip \ python3-venv python3-setuptools openssh-client libyaml-dev # hadolint ignore=DL3008,DL3059 RUN architecture=$(uname -m) && if [[ "$architecture" == "aarch64" ]]; then \ echo "aarch64: do not install helix-p4d."; else \ apt-get install --no-install-recommends -y helix-p4d; fi # compile and install universal-ctags # hadolint ignore=DL3003,DL3008 RUN apt-get install --no-install-recommends -y pkg-config automake build-essential && \ git clone https://github.com/universal-ctags/ctags /root/ctags && \ cd /root/ctags && ./autogen.sh && ./configure && make && make install && \ apt-get remove -y automake build-essential && \ apt-get -y autoremove && apt-get -y autoclean && \ cd /root && rm -rf /root/ctags && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* # 设置国内源,否则大概率不成功 RUN python3 -m pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple # Update the Python tooling in order to successfully install the opengrok-tools package. # hadolint ignore=DL3013 RUN python3 -m pip install --no-cache-dir --upgrade pip setuptools # prepare OpenGrok binaries and directories # hadolint ignore=DL3010 COPY --from=build opengrok.tar.gz /opengrok.tar.gz # hadolint ignore=DL3013 RUN mkdir -p /opengrok /opengrok/etc /opengrok/data /opengrok/src && \ tar -zxvf /opengrok.tar.gz -C /opengrok --strip-components 1 && \ rm -f /opengrok.tar.gz && \ python3 -m pip install --no-cache-dir /opengrok/tools/opengrok-tools.tar.gz && \ python3 -m pip install --no-cache-dir Flask Flask-HTTPAuth waitress # for /reindex REST endpoint handled by start.py COPY --from=build /mvn/VERSION /opengrok/VERSION # environment variables ENV SRC_ROOT /opengrok/src ENV DATA_ROOT /opengrok/data ENV URL_ROOT / ENV CATALINA_HOME /usr/local/tomcat ENV CATALINA_BASE /usr/local/tomcat ENV CATALINA_TMPDIR /usr/local/tomcat/temp ENV PATH $CATALINA_HOME/bin:$PATH ENV CLASSPATH /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar ENV JAVA_OPTS="--add-exports=java.base/jdk.internal.ref=ALL-UNNAMED --add-exports=java.base/sun.nio.ch=ALL-UNNAMED \ --add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ --add-opens=jdk.compiler/com.sun.tools.javac=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED \ --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED \ --add-opens=java.base/java.util=ALL-UNNAMED" # disable all file logging COPY docker/logging.properties /usr/local/tomcat/conf/logging.properties RUN sed -i -e 's/Valve/Disabled/' /usr/local/tomcat/conf/server.xml # add our scripts and configuration COPY docker /scripts RUN chmod -R +x /scripts # 关闭报错详情,这个会导致安全风险 RUN sed -i "s/<\/Host>/ <Valve className='org.apache.catalina.valves.ErrorReportValve' showReport='false' showServerInfo='false' \/>\n\t<\/Host>/" /usr/local/tomcat/conf/server.xml # 配置AJP协议 # 如果只希望通过 AJP访问,可以参考如下命令 移除原有的 AJP 协议配置 # RUN xmlstarlet ed -L -P -S -d '/Server/Service/Connector' /usr/local/tomcat/conf/server.xml # 增加新的协议配置 RUN sed -i "s/<\/Service>/ <Connector port='8009' protocol='AJP\/1.3' address='0.0.0.0' redirectPort='8443' secretRequired=''\/>\n <\/Service>/" /usr/local/tomcat/conf/server.xml # run WORKDIR $CATALINA_HOME EXPOSE 8080 CMD ["/scripts/start.py"] |
构建镜像:
1 |
$ podman --cgroup-manager=cgroupfs build -t opengrok-dev . |
设置容器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
$ podman stop android-4.2.2 $ podman rm android-4.2.2 # 启动一个 tomcat 容器 8081 HTTP 访问端口 8010 AJP访问端口 # 注意,Docker 镜像会自动 每隔10分钟进行一次自动索引重建,不需要手动进行索引操作, # 如果需要进行反向代理,则 OPENGROK_WEBAPP_CONTEXT 环境变量是无效的, # Docker 需要使用 URL_ROOT 进行配置 # 详细配置信息参考源代码目录下的 docker/README.md # 配置 SYNC_PERIOD_MINUTES=0 禁止周期性重建索引,但是容器重启的时候仍然会自动重建 # 多个容器的情况下,需要限制容器使用的CPU、内存资源,否则会导致宿主机内存不足,这个需要特别注意 # 这里我们分配两个核心给容器,一般限制核心也可以限制并发的Java进程,从而间接可以限制内存占用 # 同时应该限制容器内的同步线程数量 "WORKERS=1",否则极易引起宿主机的OOM # podman run -d --cpus=2 --name opengrok-android-4.2.2 -p 8081:8080/tcp -p 8010:8009 -v ~/opengrok-src/:/opengrok/src/ -v ~/opengrok-etc/:/opengrok/etc/ -v ~/opengrok-data/:/opengrok/data/ -e "URL_ROOT=Android_4.2.2" -e "SYNC_PERIOD_MINUTES=0" -e "WORKERS=1" localhost/opengrok-dev $ podman run -d --cpus=2 --name opengrok-android-4.2.2 -p 8081:8080/tcp -p 8010:8009 -v /home/podman/.dockers/opengrok/Android_4.2.2/src:/opengrok/src/ -v /home/podman/.dockers/opengrok/Android_4.2.2/etc/:/opengrok/etc/ -v /home/podman/.dockers/opengrok/Android_4.2.2/data/:/opengrok/data/ -e "URL_ROOT=Android_4.2.2" -e "SYNC_PERIOD_MINUTES=0" -e "WORKERS=1" localhost/opengrok-dev # 查看该容器 $ podman ps # 如果需要进入容器查看执行情况,参考如下命令 # podman exec -it opengrok-android-4.2.2 bash # 查看日志 # podman logs -f -t opengrok-android-4.2.2 # 每次都启动新容器方式创建servcie //--new参数,每次启动都删除旧容器,启动一个新容器 $ podman generate systemd --restart-policy=always -n --new -f android-4.2.2 |
查看启动文件:
1 |
$ cat container-opengrok-android-4.2.2.service |
内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# container-opengrok-android-4.2.2.service # autogenerated by Podman 3.4.4 # Fri Mar 22 10:41:54 CST 2024 [Unit] Description=Podman container-opengrok-android-4.2.2.service Documentation=man:podman-generate-systemd(1) Wants=network-online.target After=network-online.target RequiresMountsFor=%t/containers [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=70 ExecStartPre=/bin/rm -f %t/%n.ctr-id ExecStart=/usr/bin/podman run --cidfile=%t/%n.ctr-id --cgroups=no-conmon --rm --sdnotify=conmon --replace -d --cpus=2 --name opengrok-android-4.2.2 -p 8081:8080/tcp -p 8010:8009 -v /home/podman/.dockers/opengrok/Android_4.2.2/src:/opengrok/src/ -v /home/podman/.dockers/opengrok/Android_4.2.2/etc/:/opengrok/etc/ -v /home/podman/.dockers/opengrok/Android_4.2.2/data/:/opengrok/data/ -e "URL_ROOT=Android_4.2.2" -e "SYNC_PERIOD_MINUTES=0" -e "WORKERS=1" localhost/opengrok-dev ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id Type=notify NotifyAccess=all [Install] WantedBy=default.target |
需要额外注意的一个地方是,给出的路径必须是完整路径 “/home/podman/.dockers/opengrok/Android_4.2.2/src”,不能是 “~/.dockers/opengrok/Android_4.2.2/src”,Systemd不能正确展开 “~” ,导致路径找不到,从而在启动的时候失败,报告错误代码 125 。
另外,Android源代码目录下不能存在 .svn .git 隐藏子目,我们需要手工删除,否则会报错。参考 删除目录下所有的 .svn .git 隐藏子目
Systemd 配置,开机/重启自动启动服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# 保存到 ~/.config/systemd/user/ $ mkdir .config $ mkdir .config/systemd $ mkdir .config/systemd/user $ mv container-opengrok-android-4.2.2.service ~/.config/systemd/user/ # 以当前用户身份刷新配置文件,让其生效 $ systemctl --user daemon-reload # 设置容器开机自启,并且现在启动 $ systemctl --user enable --now ~/.config/systemd/user/container-opengrok-android-4.2.2.service # 如果需要进入容器查看执行情况,参考如下命令 # podman exec -it opengrok-android-4.2.2 bash # 查看日志 # podman logs -f -t opengrok-android-4.2.2 # 测试,重启系统,观察是否能开机自动启动 $ sudo reboot # 启动或重启服务 # systemctl --user start container-opengrok-android-4.2.2.service # systemctl --user restart container-opengrok-android-4.2.2.service # 如果启动失败,观察服务日志 # sudo journalctl -f |
Running containers with resource limits fails with a permissions error
On some systemd-based systems, non-root users do not have resource limit delegation permissions. This causes setting resource limits to fail.
Symptom
Running a container with a resource limit options will fail with an error similar to the following:
--cpus
, --cpu-period
, --cpu-quota
, --cpu-shares
:
1 |
Error: OCI runtime error: crun: the requested cgroup controller `cpu` is not available |
--cpuset-cpus
, --cpuset-mems
:
1 |
Error: OCI runtime error: crun: the requested cgroup controller `cpuset` is not available |
This means that resource limit delegation is not enabled for the current user.
Solution
You can verify whether resource limit delegation is enabled by running the following command:
1 |
$ cat "/sys/fs/cgroup/user.slice/user-$(id -u).slice/user@$(id -u).service/cgroup.controllers" |
Example output might be:
1 |
memory pids |
In the above example, cpu
and cpuset
are not listed, which means the current user does not have permission to set CPU or CPUSET limits.
If you want to enable CPU or CPUSET limit delegation for all users, you can create the file /etc/systemd/system/user@.service.d/delegate.conf
with the contents:
1 2 |
[Service] Delegate=memory pids cpu cpuset |
After logging out and logging back in, you should have permission to set CPU and CPUSET limits.
参考链接
- A Docker container for OpenGrok
- 在Ubuntu 16.04/18.04/20.04 LTS上安装OpenGrok-1.3.11/1.3.16/1.5.12/1.7.25浏览Android源码
- Ubuntu 22.04使用Podman部署Tomcat 9的详细教程
- docker hub
- dockerfile echo指定文件多行文本
- Setting up OPENGROK_WEBAPP_CONTEXT doesn't change the root directory #3054
- 在docker内设置内存与CPU限制
- 拾遗:systemctl --user
- Linux切换用户身份命令-su
- A list of common issues and solutions for Podman