Deploy Docker CE from binary files on openEuler

This guide is intended for ordinary users who wish to avoid the legacy docker-engine package in the distribution release and instead directly use Docker CE’s official static binary packages. The tutorial also installs the Docker Compose CLI plugin, configures a millisecond mirror, and verifies that Docker, custom networks, and containers can automatically recover after a system reboot using a Compose project.

The guide has been successfully tested and verified on the following environment:

  • openEuler 24.03 LTS SP3 x86_64, kernel 6.6.0-132.0.0.111.oe2403sp3.x86_64
  • Docker Engine 29.7.2
  • Docker Compose 5.5.0
  • Host SELinux Enforcing; the SELinux integration boundary for static Docker is documented in “Known Limitations”

Docker’s official documentation positions static binary installation as a manual setup method suitable for testing environments, not intended to replace system updates or be managed by the RPM database. Before using it for long-term operation, ensure you are willing to manually track and apply security updates. Reference: Install Docker Engine from binaries.


1. Install Preparation Tools

sudo dnf install -y curl tar git iptables procps-ng xz
uname -m

The following commands assume x86_64. If the output is aarch64, select the aarch64 files in the Docker and Compose download directories. This architecture has not been tested in this guide.


2. Download and Install Docker Engine

During testing, it was observed that download.docker.com may be slow or fail to connect from within China. However, domestic Docker CE mirror sites provide the same directory structure. First, attempt the official URL; if it fails, fall back to the Alibaba Cloud mirror:

mkdir -p "$HOME/docker-install"
cd "$HOME/docker-install"

DOCKER_VERSION=29.7.2
curl -fL --retry 5 --retry-all-errors \
  -o "docker-${DOCKER_VERSION}.tgz" \
  "https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz" || \
curl -fL --retry 5 --retry-all-errors \
  -o "docker-${DOCKER_VERSION}.tgz" \
  "https://mirrors.aliyun.com/docker-ce/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz"

tar -xzf "docker-${DOCKER_VERSION}.tgz"
sudo install -m 0755 docker/* /usr/local/bin/
/usr/local/bin/docker --version
/usr/local/bin/dockerd --version

The following domestic mirrors also provide the same path and file structure. If the above URLs are unreachable, you may replace the domain and path with any of the following:

  • Tencent Cloud: https://mirrors.tencent.com/docker-ce/linux/static/stable/x86_64/
  • Huawei Cloud: https://mirrors.huaweicloud.com/docker-ce/linux/static/stable/x86_64/
  • CERNET Joint Mirror: https://mirrors.cernet.edu.cn/docker-ce/linux/static/stable/x86_64/
  • Tsinghua University TUNA: https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/static/stable/x86_64/

Do not copy the version number verbatim. Before upgrading, check the official static package directory and review the release notes for the target version.


3. Create the Docker Group

Create the docker group before the first Docker startup to prevent the Docker socket from being created with root:root permissions:

sudo groupadd --force docker
sudo usermod -aG docker "$USER"

Members of the docker group effectively gain root-level access to the host. Only add trusted users to this group. See Docker’s Post-installation steps for details. Group membership changes require logging out and back in to take full effect. Until then, temporarily use sudo docker ....


4. Configure Millisecond Mirror and Container Log Rotation

Create the Docker daemon configuration:

sudo install -d -m 0755 /etc/docker
sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
{
  "registry-mirrors": [
    "https://docker.1ms.run"
  ],
  "log-driver": "local",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
EOF

sudo /usr/local/bin/dockerd --validate --config-file=/etc/docker/daemon.json

registry-mirrors configures a registry mirror for Docker daemon. The local logging driver with rotation settings prevents logs from growing indefinitely. Reference: Registry mirror and Configure logging drivers.


5. Hand Over Docker to systemd Management

Create /etc/systemd/system/docker.service:

sudo tee /etc/systemd/system/docker.service > /dev/null <<'EOF'
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
Wants=network-online.target
After=network-online.target

[Service]
Type=notify
ExecStart=/usr/local/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutStartSec=0
Restart=always
RestartSec=2
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
OOMScoreAdjust=-500

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now docker
sudo systemctl --no-pager --full status docker

Verify the configuration is active:

sudo docker info --format 'Storage={{.Driver}} Logging={{.LoggingDriver}} Mirrors={{json .RegistryConfig.Mirrors}}'

Expected output from this test:

Storage=overlayfs Logging=local Mirrors=["https://docker.1ms.run/"]

6. Install Docker Compose CLI Plugin

The Docker Engine .tgz does not include Compose. Install the official CLI plugin separately. This guide uses Compose 5.5.0 and verifies its SHA-256 hash as published in the official release:

cd "$HOME/docker-install"
COMPOSE_VERSION=v5.5.0
COMPOSE_FILE=docker-compose-linux-x86_64

curl -fL --retry 5 --retry-all-errors \
  -o "$COMPOSE_FILE" \
  "https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/${COMPOSE_FILE}"

echo 'c57ab918abd5b05ca7e7d0f275875dd1330a695074f309dc9eab1b49efafcd4b docker-compose-linux-x86_64' \
  | sha256sum -c -

sudo install -d -m 0755 /usr/local/lib/docker/cli-plugins
sudo install -m 0755 "$COMPOSE_FILE" \
  /usr/local/lib/docker/cli-plugins/docker-compose

docker compose version

If GitHub download is slow, wait in the terminal; the test completed successfully. When updating Compose, update both the version number and the checksum. New versions and hashes are available at Docker Compose Releases.


7. Validate Containers and Networks with Compose

Create a simple Nginx service that listens only on 127.0.0.1:8080. The restart: unless-stopped policy ensures Docker daemon restores containers after a host reboot. The Compose CLI does not need to run as a background service.

sudo install -d -m 0755 /opt/compose/oe-static-demo
sudo tee /opt/compose/oe-static-demo/compose.yaml > /dev/null <<'EOF'
name: oe-static-demo

services:
  web:
    image: nginx:alpine
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:80"
    networks:
      - app
    healthcheck:
      test: ["CMD-SHELL", "wget -qO- http://127.0.0.1/ > /dev/null || exit 1"]
      interval: 5s
      timeout: 3s
      retries: 12

networks:
  app:
    name: oe-static-demo-net
EOF

cd /opt/compose/oe-static-demo
docker compose config -q
docker compose up -d
docker compose ps
docker network inspect oe-static-demo-net
curl -fsS http://127.0.0.1:8080/ | grep 'Welcome to nginx'

If you still get socket permission errors after joining the docker group, log out and back in before running these commands.


8. Mandatory Reboot Verification

First, record current container and network IDs:

docker inspect oe-static-demo-web-1 --format 'container={{.Id}} restart={{.HostConfig.RestartPolicy.Name}}'
docker network inspect oe-static-demo-net --format 'network={{.Id}} containers={{len .Containers}}'

Reboot the system:

sudo reboot

After re-login, verify the state:

systemctl is-enabled docker
systemctl is-active docker
cd /opt/compose/oe-static-demo
docker compose ps
docker network inspect oe-static-demo-net \
  --format 'network={{.Id}} containers={{len .Containers}}'
docker inspect oe-static-demo-web-1 \
  --format 'status={{.State.Status}} health={{.State.Health.Status}} restart={{.HostConfig.RestartPolicy.Name}}'
curl -fsS http://127.0.0.1:8080/ | grep 'Welcome to nginx'

Expected results:

  • Docker is enabled and active
  • oe-static-demo-net still exists and contains one container
  • oe-static-demo-web-1 is running and healthy, with restart policy unless-stopped
  • Accessing 127.0.0.1:8080 returns the Nginx welcome page

In actual testing, the same container and network IDs were preserved across reboots, and all checks passed successfully.


9. Routine Checks and Upgrades

Common diagnostic commands:

systemctl status docker
journalctl -b -u docker --no-pager
docker info
docker compose ls
docker compose ps

Static binaries are not updated by dnf update. When upgrading Docker Engine, read the release notes, stop Docker, back up critical data, replace the binaries in /usr/local/bin/ with those from the new .tgz, and restart the service. Compose must also be updated independently.

Known Limitations

  • The openEuler kernel used in this test runs with cgroup v1. Docker Engine 29.7.2 logs a warning about cgroup v1 being deprecated, but all functionality and reboot tests passed. When upgrading across major versions, re-validate compatibility.
  • The host SELinux is in Enforcing mode throughout testing. The static binary package does not install container-selinux, nor does it automatically enable SELinux integration for the daemon. docker info only lists seccomp, and container processes run under the unconfined_service_t SELinux domain. This guide verifies running, networking, and recovery after reboot—not full SELinux container isolation. For production environments requiring this, install, configure, and validate a suitable SELinux policy. Do not disable host SELinux just to run Docker.

Appendix: Comparison with Distribution Package Versions

On a fresh openEuler 24.03 LTS SP3 x86_64 virtual machine using SP3 Update and Everything repositories, the following comparison was made:

Item Distribution Repository Version This Static Version
Docker Engine 18.09.0-354.oe2403sp3 29.7.2
Compose Standalone command docker-compose 1.22.0 docker compose 5.5.0
Millisecond Mirror Must be configured manually Configured as per this guide
Pulling nginx:alpine Direct Docker Hub connection times out; succeeds after mirror setup Succeeds
Compose connecting to Engine Fails Succeeds
Custom network after reboot Lost in this test; containers failed to restore Network and containers restored successfully

The distribution Compose failure is reproducible: docker-compose config parses the YAML correctly, but docker-compose ps and docker-compose up fail with the following error before connecting to the engine:

TypeError: kwargs_from_env() got an unexpected keyword argument 'ssl_version'

The test environment uses docker-compose-1.22.0-4.oe2403sp3 and python3-docker-7.0.0-2.oe2403sp3. This indicates API incompatibility between the two. After reboot, the Docker service remains active, but the custom network is gone, and containers with unless-stopped restart policy fail with network ... not found.

These findings are based on reproducible tests on a clean system and do not imply that all historical installations or third-party modified systems will behave identically.

2 Likes