From f1d2791f150a66cd6127aa5ab3b467ad186e3e20 Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Mon, 8 Dec 2025 09:19:08 -0300 Subject: [PATCH 1/2] feat: enhance Dockerfile and README for AVX and non-AVX support - Updated Dockerfile to include separate stages for AVX and non-AVX builds, with appropriate MongoDB versions. - Enhanced README with detailed instructions for using both AVX and non-AVX Docker images, including troubleshooting for AVX-related errors. - Added logging for MongoDB process exit errors, specifically for AVX-related issues. --- .github/workflows/release.yml | 25 ++++++++++- Dockerfile | 63 ++++++++++++++++++++++++---- README.md | 39 +++++++++++++++++- cmd/start.go | 78 ++++++++++++++++++++++++++++++++++- 4 files changed, 194 insertions(+), 11 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 91b811f..122c2e5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,7 +78,7 @@ jobs: provenance: true sbom: true - - name: Build and push Docker image (stage-release-all-in-one) + - name: Build and push Docker image (stage-release-all-in-one - AVX) uses: docker/build-push-action@v6 with: context: . @@ -100,3 +100,26 @@ jobs: cache-to: type=gha,mode=max provenance: true sbom: true + + - name: Build and push Docker image (stage-release-all-in-one-noavx - non-AVX) + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: true + platforms: | + linux/arm64 + linux/amd64 + target: stage-release-all-in-one-noavx + tags: | + ghcr.io/${{ github.repository }}:non-avx + ${{ steps.meta.outputs.tags }}-non-avx + labels: ${{ steps.meta.outputs.labels }} + build-args: | + VERSION=${{ fromJSON(steps.goreleaser.outputs.metadata).version }} + COMMIT=${{ fromJSON(steps.goreleaser.outputs.metadata).commit }} + COMMIT_DATE=${{ fromJSON(steps.goreleaser.outputs.metadata).date }} + cache-from: type=gha + cache-to: type=gha,mode=max + provenance: true + sbom: true diff --git a/Dockerfile b/Dockerfile index 693ebe1..bd12abf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,25 +49,72 @@ ENTRYPOINT ["/usr/local/bin/any-sync-bundle"] CMD ["start-bundle"] # -# Stage: stage-release-all-in-one +# Stage: stage-release-all-in-one (with AVX support) # FROM docker.io/redis/redis-stack-server:7.4.0-v7 AS stage-release-all-in-one +# MongoDB version configuration +ARG MONGODB_VERSION_AVX=8.0 + +# Bundle network ports +EXPOSE 33010 +EXPOSE 33020/udp + +VOLUME /data + +# Install prerequisites and MongoDB (AVX version) +RUN DEBIAN_FRONTEND=noninteractive \ + && apt-get update && apt-get install -y --no-install-recommends \ + gnupg \ + curl \ + ca-certificates \ + # Setup MongoDB AVX version repository (requires AVX) + && curl -fsSL https://pgp.mongodb.com/server-${MONGODB_VERSION_AVX}.asc | gpg -o /usr/share/keyrings/mongodb-server-${MONGODB_VERSION_AVX}.gpg --dearmor \ + && echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-${MONGODB_VERSION_AVX}.gpg ] http://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/${MONGODB_VERSION_AVX} multiverse" | tee /etc/apt/sources.list.d/mongodb-org-${MONGODB_VERSION_AVX}.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends mongodb-org-server \ + # Remove unnecessary packages + && apt-get remove -y gnupg curl python3-pip \ + && apt-get autoremove -y \ + && apt-get clean \ + && rm -rf \ + /var/lib/apt/lists/* \ + /tmp/* \ + /var/tmp/* \ + /usr/share/keyrings/mongodb-server-*.gpg \ + /etc/apt/sources.list.d/mongodb-org-*.list + +COPY --from=stage-bin /bin/any-sync-bundle /usr/local/bin/any-sync-bundle + +ENTRYPOINT ["/usr/local/bin/any-sync-bundle"] +CMD ["start-all-in-one"] + +# +# Stage: stage-release-all-in-one-noavx (without AVX support) +# +# Use Ubuntu 20.04 (focal) as base since MongoDB 4.4 only supports up to Ubuntu 20.04 +FROM ubuntu:20.04 AS stage-release-all-in-one-noavx + # Bundle network ports EXPOSE 33010 EXPOSE 33020/udp VOLUME /data -# Install prerequisites and MongoDB +# Install prerequisites, Redis Stack Server, and MongoDB 4.4 RUN DEBIAN_FRONTEND=noninteractive \ && apt-get update && apt-get install -y --no-install-recommends \ gnupg \ curl \ ca-certificates \ - # Install MongoDB - && curl -fsSL https://pgp.mongodb.com/server-8.0.asc | gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor \ - && echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] http://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/8.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-8.0.list \ + # Install Redis Stack Server + && curl -fsSL https://packages.redis.io/gpg | gpg --batch --yes --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg \ + && echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb focal main" | tee /etc/apt/sources.list.d/redis.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends redis-stack-server \ + # Setup MongoDB 4.4 repository (no AVX required - officially supported on Ubuntu 20.04) + && curl -fsSL https://pgp.mongodb.com/server-4.4.asc | gpg --batch --yes -o /usr/share/keyrings/mongodb-server-4.4.gpg --dearmor \ + && echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-4.4.gpg ] http://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list \ && apt-get update \ && apt-get install -y --no-install-recommends mongodb-org-server \ # Remove unnecessary packages @@ -78,8 +125,10 @@ RUN DEBIAN_FRONTEND=noninteractive \ /var/lib/apt/lists/* \ /tmp/* \ /var/tmp/* \ - /usr/share/keyrings/mongodb-server-8.0.gpg \ - /etc/apt/sources.list.d/mongodb-org-8.0.list + /usr/share/keyrings/mongodb-server-*.gpg \ + /usr/share/keyrings/redis-archive-keyring.gpg \ + /etc/apt/sources.list.d/mongodb-org-*.list \ + /etc/apt/sources.list.d/redis.list COPY --from=stage-bin /bin/any-sync-bundle /usr/local/bin/any-sync-bundle diff --git a/README.md b/README.md index e617851..0e5eb81 100644 --- a/README.md +++ b/README.md @@ -31,12 +31,21 @@ This is a zero-config version of the official Anytype server. It uses the same u - **Both** (comma-separated) for flexibility: `sync.example.com,192.168.1.100` ```sh +# For AVX-capable CPUs (most modern CPUs - 2011+) docker run \ -e ANY_SYNC_BUNDLE_INIT_EXTERNAL_ADDRS="192.168.100.9" \ -p 33010:33010 \ -p 33020:33020/udp \ -v $(pwd)/data:/data \ ghcr.io/grishy/any-sync-bundle:1.1.3-2025-12-01 + +# For non-AVX CPUs (older hardware) +docker run \ + -e ANY_SYNC_BUNDLE_INIT_EXTERNAL_ADDRS="192.168.100.9" \ + -p 33010:33010 \ + -p 33020:33020/udp \ + -v $(pwd)/data:/data \ + ghcr.io/grishy/any-sync-bundle:1.1.3-2025-12-01-non-avx ``` After the first run, point Anytype desktop/mobile apps at the generated client config in `./data/client-config.yml`. This is test start, check below more real configuration. @@ -46,9 +55,13 @@ After the first run, point Anytype desktop/mobile apps at the generated client c ## Available variants - **โœ… Bundle (all-in-one container)**: Bundled with MongoDB and Redis built in. -- **โœ… Bundle (solo bundle / container)**: A variant without MongoDB and Redis. You can use your own instances. + - **AVX version** (default): Uses MongoDB 8.0+ for modern CPUs with AVX support. Tag: `latest` or version tag (e.g., `v1.1.3-2025-12-01`). + - **Non-AVX version**: Uses MongoDB 4.4 for older CPUs without AVX support. Tag: `non-avx` or version tag with `-non-avx` suffix (e.g., `v1.1.3-2025-12-01-non-avx`). +- **โœ… Bundle (solo bundle / container)**: A variant without MongoDB and Redis. You can use your own instances. Tag: `minimal` or version tag with `-minimal` suffix. - **๐Ÿงถ Custom Light version[\*](#light-version-not-in-development)**: Not in development currently. +> **๐Ÿ’ก Which image to use?** Most modern CPUs (2011+) support AVX. Use the default `latest` tag. For older hardware or if you encounter AVX-related errors, use the `non-avx` tag. + ## Key features - **Easy to start**: A single command to launch the server @@ -91,13 +104,19 @@ Current version: **`v1.1.3-2025-12-01`** Pick one of the published tags, for example `v1.1.3-2025-12-01` (see [Packages](https://github.com/grishy/any-sync-bundle/pkgs/container/any-sync-bundle)). -Latest tags are also available (`ghcr.io/grishy/any-sync-bundle:latest`, `:minimal`), but using an explicit release tag keeps upgrades deliberate (my recommendation). +**Available tags:** +- `latest` / `v1.1.3-2025-12-01` - AVX version (MongoDB 8.0+) for modern CPUs +- `non-avx` / `v1.1.3-2025-12-01-non-avx` - Non-AVX version (MongoDB 4.4) for older CPUs +- `minimal` / `v1.1.3-2025-12-01-minimal` - Bundle only, external MongoDB/Redis required + +Using an explicit release tag keeps upgrades deliberate (my recommendation). - `ANY_SYNC_BUNDLE_INIT_EXTERNAL_ADDRS` multiple addresses can be added, separated by commas. - `ANY_SYNC_BUNDLE_INIT_*` variables seed the initial configuration on first start; their values are persisted to `bundle-config.yml` afterward. 1. Container (all-in-one with embedded MongoDB/Redis) + **AVX version (recommended for most users):** ```sh docker run -d \ -e ANY_SYNC_BUNDLE_INIT_EXTERNAL_ADDRS="192.168.100.9" \ @@ -109,6 +128,18 @@ Latest tags are also available (`ghcr.io/grishy/any-sync-bundle:latest`, `:minim ghcr.io/grishy/any-sync-bundle:1.1.3-2025-12-01 ``` + **Non-AVX version (for older CPUs):** + ```sh + docker run -d \ + -e ANY_SYNC_BUNDLE_INIT_EXTERNAL_ADDRS="192.168.100.9" \ + -p 33010:33010 \ + -p 33020:33020/udp \ + -v $(pwd)/data:/data \ + --restart unless-stopped \ + --name any-sync-bundle-aio \ + ghcr.io/grishy/any-sync-bundle:1.1.3-2025-12-01-non-avx + ``` + 2. Container (solo bundle, external MongoDB/Redis) ```sh docker run -d \ @@ -343,6 +374,10 @@ rm -rf ./data && tar -xzf backup-YYYYMMDD-HHMMSS.tar.gz ## Troubleshooting +- **MongoDB requires AVX (CPU instruction set) error:** + - Your CPU doesn't support AVX (Advanced Vector Extensions). MongoDB 5.0+ requires AVX. + - **Solution**: Use the `non-avx` image tag which includes MongoDB 4.4 that doesn't require AVX. + - Example: `ghcr.io/grishy/any-sync-bundle:1.1.3-2025-12-01-non-avx` - MongoDB replica set is not initiated (external DB): - Initialize manually once: `mongosh --host --eval "rs.initiate({_id:'rs0', members:[{_id:0, host:'localhost:27017'}]})"` - Replace `localhost` with the actual hostname or IP of your MongoDB server that will be used by the bundle later, if needed. diff --git a/cmd/start.go b/cmd/start.go index bee6578..412d45e 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -280,7 +280,27 @@ func newInfraProcess(ctx context.Context, name, bin string, args ...string) (*in done := make(chan error, 1) go func() { - done <- cmd.Wait() + err := cmd.Wait() + // Log process exit for debugging (especially for MongoDB AVX errors) + if err != nil { + fields := []zap.Field{ + zap.String("process", name), + zap.String("error_msg", err.Error()), + zap.Error(err), + } + + if exitErr, ok := err.(*exec.ExitError); ok { + fields = append(fields, zap.Int("exit_code", exitErr.ExitCode())) + } + + log.Debug("process exited with error", fields...) + + // Check if this is an AVX-related error for MongoDB + if name == "mongo" && isAVXRelatedError(err) { + printAVXErrorMessage(err, "process exited") + } + } + done <- err }() go streamPipe(name, stdout) @@ -355,6 +375,62 @@ func streamPipe(name string, reader io.Reader) { } } +// isAVXRelatedError checks if an error is related to AVX (illegal instruction) +func isAVXRelatedError(err error) bool { + if err == nil { + return false + } + + // Check for exit code 132 (SIGILL - Illegal Instruction) + if exitErr, ok := err.(*exec.ExitError); ok { + if exitErr.ExitCode() == 132 { + return true + } + } + + // Check error message for AVX-related keywords + errMsg := strings.ToLower(err.Error()) + avxKeywords := []string{ + "avx", + "illegal instruction", + "sigill", + "code 132", + "exit code 132", + "avx-related", + } + for _, keyword := range avxKeywords { + if strings.Contains(errMsg, keyword) { + return true + } + } + return false +} + +// printAVXErrorMessage displays a formatted AVX error message to the user +func printAVXErrorMessage(err error, context string) { + exitCode := "" + if exitErr, ok := err.(*exec.ExitError); ok { + exitCode = fmt.Sprintf(" (exit code %d)", exitErr.ExitCode()) + } + + _, _ = fmt.Fprint(os.Stderr, "\n") + _, _ = fmt.Fprint(os.Stderr, "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n") + _, _ = fmt.Fprint(os.Stderr, "โš ๏ธ MONGODB AVX ERROR DETECTED โš ๏ธ\n") + _, _ = fmt.Fprint(os.Stderr, "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n") + _, _ = fmt.Fprintf(os.Stderr, "MongoDB failed to start%s (%s)\n", exitCode, context) + _, _ = fmt.Fprint(os.Stderr, "\n") + _, _ = fmt.Fprint(os.Stderr, "This is an AVX-related error. Your CPU does not support AVX\n") + _, _ = fmt.Fprint(os.Stderr, "instructions required by MongoDB. The process was killed by the\n") + _, _ = fmt.Fprint(os.Stderr, "kernel with SIGILL (Illegal Instruction) before it could write\n") + _, _ = fmt.Fprint(os.Stderr, "any logs.\n") + _, _ = fmt.Fprint(os.Stderr, "\n") + _, _ = fmt.Fprint(os.Stderr, "SOLUTION: Use the 'non-avx' image tag:\n") + _, _ = fmt.Fprint(os.Stderr, " ghcr.io/grishy/any-sync-bundle:non-avx\n") + _, _ = fmt.Fprint(os.Stderr, "\n") + _, _ = fmt.Fprint(os.Stderr, "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n") + _, _ = fmt.Fprint(os.Stderr, "\n") +} + // waitForTCPReady polls the address until a TCP connection succeeds or timeout is reached. func waitForTCPReady(addr string, timeout time.Duration) error { ctx, cancel := context.WithTimeout(context.Background(), timeout) From c944e0c7a419e672ebf6df6e3385fd2482fef21d Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Mon, 8 Dec 2025 09:51:24 -0300 Subject: [PATCH 2/2] refactor: update Docker image build targets for AVX and non-AVX - Renamed Docker image build targets to clearly differentiate between AVX and non-AVX versions. - Adjusted tags for the Docker images to reflect the changes in target names. --- .github/workflows/release.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 122c2e5..2161d9d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,7 +78,7 @@ jobs: provenance: true sbom: true - - name: Build and push Docker image (stage-release-all-in-one - AVX) + - name: Build and push Docker image (stage-release-all-in-one-noavx - non-AVX) uses: docker/build-push-action@v6 with: context: . @@ -87,10 +87,10 @@ jobs: platforms: | linux/arm64 linux/amd64 - target: stage-release-all-in-one + target: stage-release-all-in-one-noavx tags: | - ghcr.io/${{ github.repository }}:latest - ${{ steps.meta.outputs.tags }} + ghcr.io/${{ github.repository }}:non-avx + ${{ steps.meta.outputs.tags }}-non-avx labels: ${{ steps.meta.outputs.labels }} build-args: | VERSION=${{ fromJSON(steps.goreleaser.outputs.metadata).version }} @@ -101,7 +101,7 @@ jobs: provenance: true sbom: true - - name: Build and push Docker image (stage-release-all-in-one-noavx - non-AVX) + - name: Build and push Docker image (stage-release-all-in-one - AVX) uses: docker/build-push-action@v6 with: context: . @@ -110,10 +110,10 @@ jobs: platforms: | linux/arm64 linux/amd64 - target: stage-release-all-in-one-noavx + target: stage-release-all-in-one tags: | - ghcr.io/${{ github.repository }}:non-avx - ${{ steps.meta.outputs.tags }}-non-avx + ghcr.io/${{ github.repository }}:latest + ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | VERSION=${{ fromJSON(steps.goreleaser.outputs.metadata).version }}