docker.yml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. name: Publish Docker Images
  2. on:
  3. #push:
  4. # branches:
  5. # - stable
  6. # - testing
  7. release:
  8. types:
  9. - published
  10. workflow_dispatch:
  11. inputs:
  12. tag:
  13. description: "The tag version you want to build"
  14. env:
  15. REGISTRY_IMAGE: ghcr.io/sagernet/sing-box
  16. jobs:
  17. build_binary:
  18. name: Build binary
  19. if: github.event_name != 'release' || github.event.release.target_commitish != 'oldstable'
  20. runs-on: ubuntu-latest
  21. strategy:
  22. fail-fast: true
  23. matrix:
  24. include:
  25. # Naive-enabled builds (musl)
  26. - { arch: amd64, naive: true, docker_platform: "linux/amd64" }
  27. - { arch: arm64, naive: true, docker_platform: "linux/arm64" }
  28. - { arch: "386", naive: true, docker_platform: "linux/386" }
  29. - { arch: arm, goarm: "7", naive: true, docker_platform: "linux/arm/v7" }
  30. - { arch: mipsle, gomips: softfloat, naive: true, docker_platform: "linux/mipsle" }
  31. - { arch: riscv64, naive: true, docker_platform: "linux/riscv64" }
  32. - { arch: loong64, naive: true, docker_platform: "linux/loong64" }
  33. # Non-naive builds
  34. - { arch: arm, goarm: "6", docker_platform: "linux/arm/v6" }
  35. - { arch: ppc64le, docker_platform: "linux/ppc64le" }
  36. - { arch: s390x, docker_platform: "linux/s390x" }
  37. steps:
  38. - name: Get commit to build
  39. id: ref
  40. run: |-
  41. if [[ -z "${{ github.event.inputs.tag }}" ]]; then
  42. ref="${{ github.ref_name }}"
  43. else
  44. ref="${{ github.event.inputs.tag }}"
  45. fi
  46. echo "ref=$ref"
  47. echo "ref=$ref" >> $GITHUB_OUTPUT
  48. - name: Checkout
  49. uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
  50. with:
  51. ref: ${{ steps.ref.outputs.ref }}
  52. fetch-depth: 0
  53. - name: Setup Go
  54. uses: actions/setup-go@v5
  55. with:
  56. go-version: ~1.25.8
  57. - name: Clone cronet-go
  58. if: matrix.naive
  59. run: |
  60. set -xeuo pipefail
  61. CRONET_GO_VERSION=$(cat .github/CRONET_GO_VERSION)
  62. git init ~/cronet-go
  63. git -C ~/cronet-go remote add origin https://github.com/sagernet/cronet-go.git
  64. git -C ~/cronet-go fetch --depth=1 origin "$CRONET_GO_VERSION"
  65. git -C ~/cronet-go checkout FETCH_HEAD
  66. git -C ~/cronet-go submodule update --init --recursive --depth=1
  67. - name: Regenerate Debian keyring
  68. if: matrix.naive
  69. run: |
  70. set -xeuo pipefail
  71. rm -f ~/cronet-go/naiveproxy/src/build/linux/sysroot_scripts/keyring.gpg
  72. cd ~/cronet-go
  73. GPG_TTY=/dev/null ./naiveproxy/src/build/linux/sysroot_scripts/generate_keyring.sh
  74. - name: Cache Chromium toolchain
  75. if: matrix.naive
  76. id: cache-chromium-toolchain
  77. uses: actions/cache@v4
  78. with:
  79. path: |
  80. ~/cronet-go/naiveproxy/src/third_party/llvm-build/
  81. ~/cronet-go/naiveproxy/src/gn/out/
  82. ~/cronet-go/naiveproxy/src/chrome/build/pgo_profiles/
  83. ~/cronet-go/naiveproxy/src/out/sysroot-build/
  84. key: chromium-toolchain-${{ matrix.arch }}-musl-${{ hashFiles('.github/CRONET_GO_VERSION') }}
  85. - name: Download Chromium toolchain
  86. if: matrix.naive
  87. run: |
  88. set -xeuo pipefail
  89. cd ~/cronet-go
  90. go run ./cmd/build-naive --target=linux/${{ matrix.arch }} --libc=musl download-toolchain
  91. - name: Set version
  92. run: |
  93. set -xeuo pipefail
  94. VERSION=$(go run ./cmd/internal/read_tag)
  95. echo "VERSION=${VERSION}" >> "${GITHUB_ENV}"
  96. - name: Set Chromium toolchain environment
  97. if: matrix.naive
  98. run: |
  99. set -xeuo pipefail
  100. cd ~/cronet-go
  101. go run ./cmd/build-naive --target=linux/${{ matrix.arch }} --libc=musl env >> $GITHUB_ENV
  102. - name: Set build tags
  103. run: |
  104. set -xeuo pipefail
  105. if [[ "${{ matrix.naive }}" == "true" ]]; then
  106. TAGS="$(cat release/DEFAULT_BUILD_TAGS),with_musl"
  107. else
  108. TAGS=$(cat release/DEFAULT_BUILD_TAGS_OTHERS)
  109. fi
  110. echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
  111. - name: Set shared ldflags
  112. run: |
  113. echo "LDFLAGS_SHARED=$(cat release/LDFLAGS)" >> "${GITHUB_ENV}"
  114. - name: Build (naive)
  115. if: matrix.naive
  116. run: |
  117. set -xeuo pipefail
  118. go build -v -trimpath -o sing-box -tags "${BUILD_TAGS}" \
  119. -ldflags "-X 'github.com/sagernet/sing-box/constant.Version=${VERSION}' ${LDFLAGS_SHARED} -s -w -buildid=" \
  120. ./cmd/sing-box
  121. env:
  122. CGO_ENABLED: "1"
  123. GOOS: linux
  124. GOARCH: ${{ matrix.arch }}
  125. GOARM: ${{ matrix.goarm }}
  126. GOMIPS: ${{ matrix.gomips }}
  127. - name: Build (non-naive)
  128. if: ${{ ! matrix.naive }}
  129. run: |
  130. set -xeuo pipefail
  131. go build -v -trimpath -o sing-box -tags "${BUILD_TAGS}" \
  132. -ldflags "-X 'github.com/sagernet/sing-box/constant.Version=${VERSION}' ${LDFLAGS_SHARED} -s -w -buildid=" \
  133. ./cmd/sing-box
  134. env:
  135. CGO_ENABLED: "0"
  136. GOOS: linux
  137. GOARCH: ${{ matrix.arch }}
  138. GOARM: ${{ matrix.goarm }}
  139. - name: Prepare artifact
  140. run: |
  141. platform=${{ matrix.docker_platform }}
  142. echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
  143. # Rename binary to include arch info for Dockerfile.binary
  144. BINARY_NAME="sing-box-${{ matrix.arch }}"
  145. if [[ -n "${{ matrix.goarm }}" ]]; then
  146. BINARY_NAME="${BINARY_NAME}v${{ matrix.goarm }}"
  147. fi
  148. mv sing-box "${BINARY_NAME}"
  149. echo "BINARY_NAME=${BINARY_NAME}" >> $GITHUB_ENV
  150. - name: Upload binary
  151. uses: actions/upload-artifact@v4
  152. with:
  153. name: binary-${{ env.PLATFORM_PAIR }}
  154. path: ${{ env.BINARY_NAME }}
  155. if-no-files-found: error
  156. retention-days: 1
  157. build_docker:
  158. name: Build Docker image
  159. runs-on: ubuntu-latest
  160. needs:
  161. - build_binary
  162. strategy:
  163. fail-fast: true
  164. matrix:
  165. include:
  166. - { platform: "linux/amd64" }
  167. - { platform: "linux/arm/v6" }
  168. - { platform: "linux/arm/v7" }
  169. - { platform: "linux/arm64" }
  170. - { platform: "linux/386" }
  171. # mipsle: no base Docker image available for this platform
  172. - { platform: "linux/ppc64le" }
  173. - { platform: "linux/riscv64" }
  174. - { platform: "linux/s390x" }
  175. - { platform: "linux/loong64", base_image: "ghcr.io/loong64/alpine:edge" }
  176. steps:
  177. - name: Get commit to build
  178. id: ref
  179. run: |-
  180. if [[ -z "${{ github.event.inputs.tag }}" ]]; then
  181. ref="${{ github.ref_name }}"
  182. else
  183. ref="${{ github.event.inputs.tag }}"
  184. fi
  185. echo "ref=$ref"
  186. echo "ref=$ref" >> $GITHUB_OUTPUT
  187. - name: Checkout
  188. uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
  189. with:
  190. ref: ${{ steps.ref.outputs.ref }}
  191. fetch-depth: 0
  192. - name: Prepare
  193. run: |
  194. platform=${{ matrix.platform }}
  195. echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
  196. - name: Download binary
  197. uses: actions/download-artifact@v5
  198. with:
  199. name: binary-${{ env.PLATFORM_PAIR }}
  200. path: .
  201. - name: Prepare binary
  202. run: |
  203. # Find and make the binary executable
  204. chmod +x sing-box-*
  205. ls -la sing-box-*
  206. - name: Setup QEMU
  207. uses: docker/setup-qemu-action@v3
  208. - name: Setup Docker Buildx
  209. uses: docker/setup-buildx-action@v3
  210. - name: Login to GitHub Container Registry
  211. uses: docker/login-action@v3
  212. with:
  213. registry: ghcr.io
  214. username: ${{ github.repository_owner }}
  215. password: ${{ secrets.GITHUB_TOKEN }}
  216. - name: Docker meta
  217. id: meta
  218. uses: docker/metadata-action@v5
  219. with:
  220. images: ${{ env.REGISTRY_IMAGE }}
  221. - name: Build and push by digest
  222. id: build
  223. uses: docker/build-push-action@v6
  224. with:
  225. platforms: ${{ matrix.platform }}
  226. context: .
  227. file: Dockerfile.binary
  228. build-args: |
  229. BASE_IMAGE=${{ matrix.base_image || 'alpine' }}
  230. labels: ${{ steps.meta.outputs.labels }}
  231. outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
  232. - name: Export digest
  233. run: |
  234. mkdir -p /tmp/digests
  235. digest="${{ steps.build.outputs.digest }}"
  236. touch "/tmp/digests/${digest#sha256:}"
  237. - name: Upload digest
  238. uses: actions/upload-artifact@v4
  239. with:
  240. name: digests-${{ env.PLATFORM_PAIR }}
  241. path: /tmp/digests/*
  242. if-no-files-found: error
  243. retention-days: 1
  244. merge:
  245. if: github.event_name != 'push'
  246. runs-on: ubuntu-latest
  247. needs:
  248. - build_docker
  249. steps:
  250. - name: Get commit to build
  251. id: ref
  252. run: |-
  253. if [[ -z "${{ github.event.inputs.tag }}" ]]; then
  254. ref="${{ github.ref_name }}"
  255. else
  256. ref="${{ github.event.inputs.tag }}"
  257. fi
  258. echo "ref=$ref"
  259. echo "ref=$ref" >> $GITHUB_OUTPUT
  260. if [[ $ref == *"-"* ]]; then
  261. latest=latest-beta
  262. else
  263. latest=latest
  264. fi
  265. echo "latest=$latest"
  266. echo "latest=$latest" >> $GITHUB_OUTPUT
  267. - name: Download digests
  268. uses: actions/download-artifact@v5
  269. with:
  270. path: /tmp/digests
  271. pattern: digests-*
  272. merge-multiple: true
  273. - name: Set up Docker Buildx
  274. uses: docker/setup-buildx-action@v3
  275. - name: Login to GitHub Container Registry
  276. uses: docker/login-action@v3
  277. with:
  278. registry: ghcr.io
  279. username: ${{ github.repository_owner }}
  280. password: ${{ secrets.GITHUB_TOKEN }}
  281. - name: Create manifest list and push
  282. if: github.event_name != 'push'
  283. working-directory: /tmp/digests
  284. run: |
  285. docker buildx imagetools create \
  286. -t "${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.latest }}" \
  287. -t "${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.ref }}" \
  288. $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
  289. - name: Inspect image
  290. if: github.event_name != 'push'
  291. run: |
  292. docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.latest }}
  293. docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.ref }}