Skip to content

Commit 3fd67dd

Browse files
docs(blog): add docker and docusaurus deployment articles
主要变更: - 添加 Docker Hub 到 Azure ACR 镜像同步指南 - 使用 GitHub Actions + image-syncer 自动化同步 - 增量同步、断点续传、并发控制 - 包含完整的风险评估和故障排查 - 添加 Docusaurus + GitHub Actions 自动部署教程 - 从手动部署到自动化部署的实践记录 - GitHub Pages 集成配置 - 权限、路径、subpath 等常见坑点解决方案 Co-Authored-By: Hagicode <[email protected]> Signed-off-by: newbe36524 <[email protected]>
1 parent 77c39b0 commit 3fd67dd

2 files changed

Lines changed: 587 additions & 0 deletions

File tree

Lines changed: 382 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,382 @@
1+
---
2+
title: "How to Use GitHub Actions + image-syncer for Automated Image Sync from Docker Hub to Azure ACR"
3+
date: 2026-01-25
4+
truncate: true
5+
englishSlug: "how-to-sync-docker-hub-to-azure-acr-with-github"
6+
tags: [Docker Hub, Azure ACR, GitHub Actions, Image Sync, DevOps]
7+
---
8+
9+
## Automating Image Sync from Docker Hub to Azure ACR
10+
11+
> This article explains how to use GitHub Actions and the image-syncer tool to automate image synchronization from Docker Hub to Azure Container Registry, solving the problem of slow Docker Hub access in mainland China and some Azure regions, while improving image availability and deployment efficiency in Azure environments.
12+
13+
## Background / Introduction
14+
15+
The HagiCode project uses Docker images as its core runtime components, with the main images hosted on Docker Hub. As the project has evolved and Azure deployment needs have grown, we encountered the following pain points:
16+
- Slow image pulls, because access to Docker Hub is limited in mainland China and some Azure regions
17+
- Relying on a single image source creates a single point of failure risk
18+
- Using Azure Container Registry in Azure environments provides better network performance and integration experience
19+
20+
To solve these problems, we need to establish an automated image synchronization mechanism that regularly syncs images from Docker Hub to Azure ACR, ensuring users get faster image pull speeds and higher availability in Azure environments.
21+
22+
## About HagiCode
23+
24+
We are building HagiCode, an AI-driven coding assistant that makes development smarter, more convenient, and more enjoyable.
25+
26+
Smart: AI assistance throughout the entire process, from idea to code, boosting coding efficiency several times over. Convenient: Multi-threaded concurrent operations make full use of resources and keep the development workflow smooth. Fun: Gamification and an achievement system make coding less dull and more rewarding.
27+
28+
The project is evolving rapidly. If you are interested in technical writing, knowledge management, or AI-assisted development, welcome to check it out on GitHub.
29+
30+
## Technical Solution Comparison
31+
32+
When defining the solution, we compared multiple technical approaches:
33+
34+
### 1. image-syncer (final choice)
35+
- Incremental sync: only synchronizes changed image layers, significantly reducing network transfer
36+
- Resume support: synchronization can resume after network interruptions
37+
- Concurrency control: supports configurable concurrency to improve large image sync efficiency
38+
- Robust error handling: built-in retry mechanism for failures (3 times by default)
39+
- Lightweight deployment: single binary with no dependencies
40+
- Multi-registry support: compatible with Docker Hub, Azure ACR, Harbor, and more
41+
42+
### 2. Docker CLI
43+
- No incremental sync support: each run requires pulling the full image content
44+
- Lower efficiency: large network transfer volume and longer execution time
45+
- Simple and easy to use: relies on familiar `docker pull` / `docker push` commands
46+
47+
### 3. Azure CLI
48+
- Higher complexity: requires Azure CLI authentication setup
49+
- Functional limitations: `az acr import` is relatively limited
50+
- Native integration: integrates well with Azure services
51+
52+
## Architecture Design Decisions
53+
54+
### Decision 1: Set the sync frequency to daily at 00:00 UTC
55+
- Balances image freshness with resource consumption
56+
- Avoids peak business hours and reduces impact on other operations
57+
- Docker Hub images are usually updated after daily builds
58+
59+
### Decision 2: Sync all image tags
60+
- Maintains full consistency with Docker Hub
61+
- Provides flexible version choices for users
62+
- Simplifies sync logic by avoiding complex tag filtering rules
63+
64+
### Decision 3: Store credentials in GitHub Secrets
65+
- Natively supported by GitHub Actions with strong security
66+
- Simple to configure and easy to manage and maintain
67+
- Supports repository-level access control
68+
69+
## Risk Assessment and Mitigation
70+
71+
### Risk 1: Azure ACR credential leakage
72+
- Use GitHub Secrets for encrypted storage
73+
- Rotate ACR passwords regularly
74+
- Limit ACR account permissions to push-only
75+
- Monitor ACR access logs
76+
77+
### Risk 2: Sync failures causing image inconsistency
78+
- image-syncer includes a built-in incremental sync mechanism
79+
- Automatic retry on failure (3 times by default)
80+
- Detailed error logs and failure notifications
81+
- Resume support
82+
83+
### Risk 3: Excessive resource consumption
84+
- Incremental sync reduces network transfer
85+
- Configurable concurrency (`10` in the current setup)
86+
- Monitor the number and size of synchronized images
87+
- Run synchronization during off-peak hours
88+
89+
## Core Solution
90+
91+
We use an automated GitHub Actions + image-syncer solution to synchronize images from Docker Hub to Azure ACR.
92+
93+
## Implementation Steps
94+
95+
### 1. Preparation
96+
- Create or confirm an Azure Container Registry in Azure Portal
97+
- Create ACR access credentials (username and password)
98+
- Confirm access permissions for the Docker Hub image repository
99+
100+
### 2. Configure GitHub Secrets
101+
Add the following secrets in the GitHub repository settings:
102+
- AZURE_ACR_USERNAME: Azure ACR username
103+
- AZURE_ACR_PASSWORD: Azure ACR password
104+
105+
### 3. Create the GitHub Actions workflow
106+
Configure the workflow in `.github/workflows/sync-docker-acr.yml`:
107+
- Scheduled trigger: every day at 00:00 UTC
108+
- Manual trigger: supports `workflow_dispatch`
109+
- Extra trigger: run when the `publish` branch receives a push (for fast synchronization)
110+
111+
### 4. Workflow execution flow
112+
113+
| Sequence | Participant | Action | Description |
114+
| --- | --- | --- | --- |
115+
| 1 | GitHub Actions | Trigger workflow | Triggered by schedule, manual run, or a push to the `publish` branch |
116+
| 2 | GitHub Actions → image-syncer | Download and run the sync tool | Enter the actual sync phase |
117+
| 3 | image-syncer → Docker Hub | Fetch image manifests and tag list | Read source repository metadata |
118+
| 4 | image-syncer → Azure ACR | Fetch existing image information from the target repository | Determine the current target-side state |
119+
| 5 | image-syncer | Compare source and target differences | Identify image layers that need to be synchronized |
120+
| 6 | image-syncer → Docker Hub | Pull changed image layers | Transfer only the content that needs updating |
121+
| 7 | image-syncer → Azure ACR | Push changed image layers | Complete incremental synchronization |
122+
| 8 | image-syncer → GitHub Actions | Return synchronization statistics | Includes results, differences, and error information |
123+
| 9 | GitHub Actions | Record logs and upload artifacts | Useful for follow-up auditing and troubleshooting |
124+
125+
## GitHub Actions Workflow Implementation
126+
127+
Here is the actual workflow configuration in use (`.github/workflows/sync-docker-acr.yml`):
128+
129+
```yaml
130+
name: Sync Docker Image to Azure ACR
131+
132+
on:
133+
schedule:
134+
- cron: "0 0 * * *" # Every day at 00:00 UTC
135+
workflow_dispatch: # Manual trigger
136+
push:
137+
branches: [publish]
138+
139+
permissions:
140+
contents: read
141+
142+
jobs:
143+
sync:
144+
runs-on: ubuntu-latest
145+
146+
steps:
147+
- name: Checkout code
148+
uses: actions/checkout@v4
149+
150+
- name: Download image-syncer
151+
run: |
152+
# Download the image-syncer binary
153+
wget https://github.com/AliyunContainerService/image-syncer/releases/download/v1.5.5/image-syncer-v1.5.5-linux-amd64.tar.gz
154+
tar -zxvf image-syncer-v1.5.5-linux-amd64.tar.gz
155+
chmod +x image-syncer
156+
157+
- name: Create auth config
158+
run: |
159+
# Generate the authentication configuration file (YAML format)
160+
cat > auth.yaml <<EOF
161+
hagicode.azurecr.io:
162+
username: "${{ secrets.AZURE_ACR_USERNAME }}"
163+
password: "${{ secrets.AZURE_ACR_PASSWORD }}"
164+
EOF
165+
166+
- name: Create images config
167+
run: |
168+
# Generate the image synchronization configuration file (YAML format)
169+
cat > images.yaml <<EOF
170+
docker.io/newbe36524/hagicode: hagicode.azurecr.io/hagicode
171+
EOF
172+
173+
- name: Run image-syncer
174+
run: |
175+
# Run synchronization (using the newer --auth and --images parameters)
176+
./image-syncer --auth=./auth.yaml --images=./images.yaml --proc=10 --retries=3
177+
178+
- name: Upload logs
179+
if: always()
180+
uses: actions/upload-artifact@v4
181+
with:
182+
name: sync-logs
183+
path: image-syncer-*.log
184+
retention-days: 7
185+
```
186+
187+
## Configuration Details
188+
189+
### 1. Trigger conditions
190+
- Scheduled trigger: `cron: "0 0 * * *"` - runs every day at 00:00 UTC
191+
- Manual trigger: `workflow_dispatch` - allows users to run it manually in the GitHub UI
192+
- Push trigger: `push: branches: [publish]` - triggered when the publish branch receives a push (for fast synchronization)
193+
194+
### 2. Authentication configuration (`auth.yaml`)
195+
```yaml
196+
hagicode.azurecr.io:
197+
username: "${{ secrets.AZURE_ACR_USERNAME }}"
198+
password: "${{ secrets.AZURE_ACR_PASSWORD }}"
199+
```
200+
201+
### 3. Image sync configuration
202+
```yaml
203+
docker.io/newbe36524/hagicode: hagicode.azurecr.io/hagicode
204+
```
205+
This configuration means synchronizing all tags from `docker.io/newbe36524/hagicode` to `hagicode.azurecr.io/hagicode`
206+
207+
### 4. image-syncer parameters
208+
- `--auth=./auth.yaml`: path to the authentication configuration file
209+
- `--images=./images.yaml`: path to the image synchronization configuration file
210+
- `--proc=10`: set concurrency to `10`
211+
- `--retries=3`: retry failures `3` times
212+
213+
## GitHub Secrets Configuration Checklist
214+
215+
Configure the following in `Settings → Secrets and variables → Actions` in the GitHub repository:
216+
217+
| Secret Name | Description | Example Value | How to Get It |
218+
|------------|------|--------|---------|
219+
| AZURE_ACR_USERNAME | Azure ACR username | hagicode | Azure Portal → ACR → Access keys |
220+
| AZURE_ACR_PASSWORD | Azure ACR password | xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | Azure Portal → ACR → Access keys → Password |
221+
222+
## Usage Instructions
223+
224+
### 1. Manually trigger synchronization
225+
1. Open the `Actions` tab of the GitHub repository
226+
2. Select the `Sync Docker Image to Azure ACR` workflow
227+
3. Click the `Run workflow` button
228+
4. Choose the branch and click `Run workflow` to confirm
229+
230+
### 2. View synchronization logs
231+
1. Click a specific workflow run record on the `Actions` page
232+
2. View the execution logs for each step
233+
3. Download the `sync-logs` file from the `Artifacts` section at the bottom of the page
234+
235+
### 3. Verify synchronization results
236+
```bash
237+
# Log in to Azure ACR
238+
az acr login --name hagicode
239+
240+
# List images and their tags
241+
az acr repository show-tags --name hagicode --repository hagicode --output table
242+
```
243+
244+
## Notes and Best Practices
245+
246+
### 1. Security recommendations
247+
- Rotate Azure ACR passwords regularly (recommended every 90 days)
248+
- Use a dedicated ACR service account with push-only permissions
249+
- Monitor ACR access logs to detect abnormal access in time
250+
- Do not output credentials in logs
251+
- Do not commit credentials to the code repository
252+
253+
### 2. Performance optimization
254+
- Adjust the `--proc` parameter: tune concurrency based on network bandwidth (recommended `5-20`)
255+
- Monitor synchronization time: if it takes too long, consider reducing concurrency
256+
- Clean up logs regularly: set a reasonable `retention-days` value (`7` days in the current setup)
257+
258+
### 3. Troubleshooting
259+
260+
#### Issue 1: Authentication failed
261+
```
262+
Error: failed to authenticate to hagicode.azurecr.io
263+
```
264+
Solution:
265+
1. Check whether GitHub Secrets are configured correctly
266+
2. Verify whether the Azure ACR password has expired
267+
3. Confirm whether the ACR service account permissions are correct
268+
269+
#### Issue 2: Network timeout
270+
```
271+
Error: timeout waiting for response
272+
```
273+
Solution:
274+
1. Check network connectivity
275+
2. Reduce concurrency (`--proc` parameter)
276+
3. Wait for the network to recover and trigger the workflow again
277+
278+
#### Issue 3: Incomplete image synchronization
279+
```
280+
Warning: some tags failed to sync
281+
```
282+
Solution:
283+
1. Check the synchronization logs to identify failed tags
284+
2. Manually trigger the workflow to synchronize again
285+
3. Verify that the source image on Docker Hub is working properly
286+
287+
### 4. Monitoring and alerts
288+
- Regularly check the `Actions` page to confirm workflow run status
289+
- Configure GitHub notifications to receive workflow failure alerts promptly
290+
- Monitor Azure ACR storage usage
291+
- Regularly verify tag consistency
292+
293+
## Frequently Asked Questions and Solutions
294+
295+
### Q1: How do I sync specific tags instead of all tags?
296+
297+
Modify the `images.yaml` configuration file:
298+
```yaml
299+
# Sync only the latest and v1.0 tags
300+
docker.io/newbe36524/hagicode:latest: hagicode.azurecr.io/hagicode:latest
301+
docker.io/newbe36524/hagicode:v1.0: hagicode.azurecr.io/hagicode:v1.0
302+
```
303+
304+
### Q2: How do I sync multiple image repositories?
305+
306+
Add multiple lines in `images.yaml`:
307+
```yaml
308+
docker.io/newbe36524/hagicode: hagicode.azurecr.io/hagicode
309+
docker.io/newbe36524/another-image: hagicode.azurecr.io/another-image
310+
```
311+
312+
### Q3: How do I retry after a synchronization failure?
313+
- Automatic retry: image-syncer includes a built-in retry mechanism (`3` times by default)
314+
- Manual retry: click `Re-run all jobs` on the GitHub Actions page
315+
316+
### Q4: How do I view detailed synchronization progress?
317+
- View real-time logs on the `Actions` page
318+
- Download the `sync-logs` artifact to see the full log file
319+
- The log file includes the synchronization status and transfer speed for each tag
320+
321+
### Q5: How long does synchronization take?
322+
- Initial full synchronization: typically takes `10-30` minutes depending on image size
323+
- Incremental synchronization: usually `2-5` minutes if image changes are small
324+
- Time depends on network bandwidth, image size, and concurrency settings
325+
326+
## Suggested Enhancements
327+
328+
### 1. Add synchronization notifications
329+
Add a notification step to the workflow:
330+
```yaml
331+
- name: Notify on success
332+
if: success()
333+
run: |
334+
echo "Docker images synced successfully to Azure ACR"
335+
```
336+
337+
### 2. Implement image tag filtering
338+
Add tag filtering logic to the workflow:
339+
```yaml
340+
- name: Filter tags
341+
run: |
342+
# Sync only tags that start with v
343+
echo "docker.io/newbe36524/hagicode:v* : hagicode.azurecr.io/hagicode:v*" > images.yaml
344+
```
345+
346+
### 3. Add a synchronization statistics report
347+
```yaml
348+
- name: Generate report
349+
if: always()
350+
run: |
351+
echo "## Sync Report" >> $GITHUB_STEP_SUMMARY
352+
echo "- Total tags: $(grep -c 'synced' image-syncer-*.log)" >> $GITHUB_STEP_SUMMARY
353+
echo "- Sync time: ${{ steps.sync.outputs.duration }}" >> $GITHUB_STEP_SUMMARY
354+
```
355+
356+
## Conclusion
357+
358+
With the method introduced in this article, we successfully implemented automated image synchronization from Docker Hub to Azure ACR. This solution uses the scheduled and manual trigger capabilities of GitHub Actions together with the incremental synchronization and error-handling features of image-syncer to ensure timely and consistent image synchronization.
359+
360+
We also discussed security best practices, performance optimization, troubleshooting, and other related topics to help users better manage and maintain this synchronization mechanism. We hope this article provides valuable reference material for developers who need to deploy Docker images in Azure environments.
361+
362+
## References
363+
- [HagiCode project GitHub repository](https://github.com/HagiCode-org/site)
364+
- [image-syncer official documentation](https://github.com/AliyunContainerService/image-syncer)
365+
- [Azure Container Registry official documentation](https://learn.microsoft.com/zh-cn/azure/container-registry/)
366+
- [GitHub Actions official documentation](https://docs.github.com/zh-cn/actions)
367+
368+
---
369+
370+
## Reader Interaction
371+
372+
Thank you for reading. If you found this article useful, please click the like button below 👍 so more people can discover it.
373+
374+
## AI Assistance Disclosure
375+
376+
This content was created with AI-assisted collaboration, reviewed by me, and reflects my own views and position.
377+
378+
## Metadata
379+
380+
- **Author:** [newbe36524](https://www.newbe.pro)
381+
- **Article URL:** [https://hagicode.com/blog/2026/01/25/how-to-sync-docker-hub-to-azure-acr-with-github](https://hagicode.com/blog/2026/01/25/how-to-sync-docker-hub-to-azure-acr-with-github)
382+
- **Copyright:** Unless otherwise stated, all articles on this blog are licensed under BY-NC-SA. Please include attribution when reprinting.

0 commit comments

Comments
 (0)