docker.yml 10 KB

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