We have been running 1C:Enterprise on Linux containers for several years now. Every time the platform version bumps, somebody on the team rediscovers why the official tarball plus a hand-written systemd unit is a bad idea. This post is the layout we settled on: one image per platform version, a stable data volume, a separate PostgreSQL container, and a cluster registry that survives docker compose down -v mistakes.
Nothing here is exotic. The point is that the moving parts are small enough that a junior engineer can rebuild the stack from scratch in an hour.
What we are actually deploying
Three containers, one network, two volumes:
onec-server—ragent,rmngr,rphostprocesses from the platform tarball.onec-pg— PostgreSQL build patched for 1C (the standard fork from PostgresPro or the community patches, depending on what your license allows).onec-ws— optional Apache or nginx in front of the web publication, only if you publish bases over HTTP.
Volumes:
onec-srvinfo— the cluster registry under/home/usr1cv8/.1cv8/1C/1cv8/srvinfo. This is the volume you must never lose. It holds cluster topology, infobase list, security settings.onec-pgdata— Postgres data directory. Same rules as any other Postgres deployment.
The image: pinned, not floating
We build one image per platform version and tag it explicitly. No latest. The platform installer tarball goes in by build arg, so the Dockerfile is the same for every version.
FROM debian:12-slim
ARG ONEC_VERSION
ARG ONEC_TARBALL=server64_${ONEC_VERSION}.tar.gz
RUN apt-get update && apt-get install -y --no-install-recommends \
imagemagick libfreetype6 libgsf-1-114 libglib2.0-0 \
libwebkit2gtk-4.0-37 fonts-liberation ttf-mscorefonts-installer \
locales tzdata ca-certificates curl && \
sed -i '/ru_RU.UTF-8/s/^# //' /etc/locale.gen && locale-gen && \
rm -rf /var/lib/apt/lists/*
ENV LANG=ru_RU.UTF-8 LC_ALL=ru_RU.UTF-8
COPY ${ONEC_TARBALL} /tmp/
RUN mkdir /tmp/onec && tar -xzf /tmp/${ONEC_TARBALL} -C /tmp/onec && \
cd /tmp/onec && ./setup-full-${ONEC_VERSION}-x86_64.run --mode unattended && \
rm -rf /tmp/onec /tmp/${ONEC_TARBALL}
USER usr1cv8
WORKDIR /home/usr1cv8
EXPOSE 1540 1541 1560-1591
CMD ["/opt/1cv8/x86_64/current/ragent", "-daemon"]
Build it like this:
docker build \
--build-arg ONEC_VERSION=8.3.24.1234 \
-t registry.local/onec:8.3.24.1234 .
Do not bake the platform tarball into a public registry. The license is per-customer; treat the image as a private artifact.
Compose file
services:
onec-pg:
image: registry.local/postgres-1c:15
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/pg_password
POSTGRES_DB: postgres
TZ: Europe/Belgrade
volumes:
- onec-pgdata:/var/lib/postgresql/data
secrets: [pg_password]
shm_size: 1g
networks: [onec]
onec-server:
image: registry.local/onec:8.3.24.1234
depends_on: [onec-pg]
volumes:
- onec-srvinfo:/home/usr1cv8/.1cv8/1C/1cv8/srvinfo
ports:
- "1540:1540"
- "1541:1541"
- "1560-1591:1560-1591"
networks: [onec]
restart: unless-stopped
volumes:
onec-pgdata:
onec-srvinfo:
networks:
onec:
secrets:
pg_password:
file: ./secrets/pg_password
The port range 1560-1591 is what rphost workers grab. If you constrain it, rphost will silently refuse to start more workers under load.
PostgreSQL: the boring part that breaks first
A generic Postgres tune is fine for small infobases. Anything above a few dozen GB needs the usual treatment:
shared_buffers~ 25% of container RAM.work_mem~ 64–128 MB. 1C generates a lot of small sorts.max_connections~ 200–500. 1C opens connections aggressively.effective_cache_size~ 60–70% of RAM.- Disable
huge_pagesunless you actually configured them on the host. temp_file_limitset high. Reposting documents on a closed period will write GB of temp.
Mount postgresql.conf as a separate file so you can change it without rebuilding the image:
volumes:
- onec-pgdata:/var/lib/postgresql/data
- ./pg/postgresql.conf:/etc/postgresql/postgresql.conf:ro
command: postgres -c config_file=/etc/postgresql/postgresql.conf
The upgrade flow
This is the part that bites teams who never wrote it down. The platform version is upgraded much more often than the configuration. We follow a fixed sequence:
- Build and push the new image:
registry.local/onec:8.3.25.xxxx. - Stop user sessions through the cluster console (or
rac session terminate). - Take a
pg_dumpof every infobase. Yes, a filesystem snapshot ofonec-pgdatais faster, but a logical dump is what you actually want when something goes wrong with 1C-specific catalog bits. docker compose downfor theonec-serverservice only. Postgres stays up.- Update the image tag in
compose.yaml,docker compose up -d onec-server. - Watch
docker logs -f onec-server. The first start on a new platform version rewrites parts ofsrvinfo. If it crashes here, do not restart in a loop — investigate. - Open each infobase in Designer to let it apply the platform-level migrations. This step cannot be skipped on major bumps.
Because srvinfo lives in a named volume and the image is immutable, rolling back is docker compose up -d onec-server with the previous tag. The cluster registry is forward-and-backward compatible across minor versions, less so across major ones — keep the dump.
If you publish bases over HTTP, the web extension version must match the platform version. We rebuild the
onec-wsimage in the same CI job to keep them in lockstep.
Things we learned the hard way
- Locales matter. A container without
ru_RU.UTF-8will startragentand then mangle every string from the infobase. Generate the locale at build time. shm_sizeon Postgres. The default 64 MB is enough to make parallel queries fail with a generic shared memory error. Bump it.- Do not bind-mount
srvinfofrom the host onto Linux with weird permissions. Theusr1cv8UID inside the container will be different from your host user, andragentwill silently store nothing. Use a named volume. rphostmemory limits. Set--memoryon the container generously, then use cluster-level rphost recycling instead of letting the OOM killer end your day.- Time zone. If the container TZ does not match what 1C expects, posting documents around midnight produces date-shifted entries. Set
TZexplicitly in both containers.
What we would change next
We are slowly moving the cluster onto Kubernetes with a StatefulSet for onec-server and an external managed Postgres. The image and the volume layout above port over without changes — which is the entire point of keeping the Compose setup boring. If the upgrade ritual fits on one page of a runbook, the platform team can ship a new 1C version on a Friday afternoon without anyone losing sleep. Almost.