M1 Mac使用Docker Buildx构建Google Cloud Run镜像挂起求助
问题:Docker Buildx构建linux/amd64镜像时进程卡住,本地构建正常
正在将MEAN栈前端发布到Google Container Registry(GCR),使用Docker Buildx构建linux/amd64架构镜像时,构建进程始终无法完成(已等待数小时)。本地直接执行npm run build-prod仅需几秒即可完成。
构建与部署命令
构建命令:
docker buildx build --platform linux/amd64 -t gcr.io/project_id/:latest -f Dockerfile.frontend . --push
部署命令:
gcloud run deploy (removed) --image gcr.io/project_id/:latest --platform managed --region europe-west1 --allow-unauthenticated
相关配置文件
package.json
{ "name": "frontend", "version": "0.0.1", "license": "", "scripts": { "build-dev": "ng build --configuration=development,localized", "build-prod": "ng build --configuration=production,localized --verbose" }, "private": true, "dependencies": { "@angular/animations": "16.2.12", "@angular/cdk": "16.2.12", "@angular/common": "16.2.12", "@angular/compiler": "16.2.12", "@angular/core": "16.2.12", "@angular/forms": "16.2.12", "@angular/localize": "^16.2.3", "@angular/platform-browser": "16.2.12", "@angular/platform-browser-dynamic": "16.2.12", "@angular/router": "16.2.12", "@fullcalendar/core": "^6.1.8", "@fullcalendar/daygrid": "^6.1.8", "@fullcalendar/interaction": "^6.1.8", "@fullcalendar/timegrid": "^6.1.8", "@google-cloud/translate": "^8.0.1", "@googlemaps/js-api-loader": "^1.16.2", "@halftome/szamlazz-client": "^1.1.0", "@swc-node/register": "^1.6.7", "@swc/core": "^1.3.88", "axios": "^1.5.0", "chart.js": "^4.4.0", "file-saver": "^2.0.5", "html2canvas": "^1.4.1", "jspdf": "^2.5.1", "authpal-client": "^1.4.3", "jszip": "^3.10.1", "luxon": "^3.4.3", "primeflex": "^3.3.1", "primeicons": "^6.0.1", "primeng": "16.3.1", "prismjs": "^1.29.0", "rxjs": "~7.8.1", "tslib": "^2.3.0", "sass": "^1.69.4", "web-animations-js": "^2.3.2", "xlsx": "^0.18.5", "zone.js": "^0.13.1" }, "devDependencies": { "@angular-devkit/build-angular": "~16.2.0", "@angular-devkit/core": "~16.2.0", "@angular-devkit/schematics": "~16.2.0", "@angular/cli": "~16.2.0", "@angular/compiler-cli": "~16.2.0", "@angular/language-service": "~16.2.0", "@schematics/angular": "~16.2.0", "@types/google.maps": "^3.54.0", "@types/luxon": "^3.3.2", "typescript": "~5.1.3", "@types/file-saver": "^2.0.5", "@angular/localize": "^16.2.0" } }
Dockerfile.frontend
# ---- Base Node ---- FROM node:alpine as base # Set working directory WORKDIR /usr/src/app # Copy package.json and package-lock.json (or yarn.lock) COPY package*.json ./ # Install dependencies RUN npm install # Copy application source code COPY . . # Build the application RUN npm run build-prod # ---- Nginx ---- FROM nginx:alpine as runner # Copy nginx configuration from base stage COPY nginx.conf /etc/nginx/conf.d/default.conf # Copy built application files from base stage COPY --from=base /usr/src/app/dist /usr/share/nginx/html/ # Expose port EXPOSE 80 # Run the application CMD ["nginx", "-g", "daemon off;"]
nginx.conf
map $http_accept_language $accept_language { ~*^hu hu; ~*^en en; default en; } server { listen 80; resolver 8.8.8.8; set $backend_name (removed); server_name $backend_name; root /usr/share/nginx/html; index index.html index.htm; client_max_body_size 32m; add_header Content-Security-Policy "default-src 'self'; connect-src 'self' https://maps.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://cdn.jsdelivr.net; font-src 'self' data:; script-src 'self' 'unsafe-inline' https://maps.googleapis.com https://editor.unlayer.com; frame-src 'self' https://editor.unlayer.com; frame-ancestors 'self'"; add_header X-Frame-Options "SAMEORIGIN" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains"; add_header X-Content-Type-Options "nosniff" always; gzip on; gzip_static on; gzip_comp_level 4; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; gzip_min_length 1000; location = /favicon.ico { try_files /hu/favicon.ico /en/favicon.ico =404; } location ~* \.css$ { add_header Content-Type text/css; } location ~* \.png$ { add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"; expires off; } location ~ ^/(hu|en)/ { try_files $uri $uri/ /$1/index.html?$args; } location ~ /(hu|en)?/vendor.js { expires 7d; add_header Cache-Control "public, max-age=604800"; add_header Last-Modified $date_gmt; add_header ETag $request_uri; } location /api { proxy_ssl_server_name on; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; proxy_set_header Host $backend_name(removed); proxy_pass https://$backend_name(removed):443; proxy_read_timeout 300s; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } location / { if ($request_uri = '/') { rewrite ^/$ /$accept_language/ permanent; } try_files $uri $uri/ /$accept_language/index.html?$args; } error_page 500 502 503 504 /50x.html; error_page 404 =200 /en/index.html; location = /50x.html { internal; } }
angular.json
{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "projectname": { "projectType": "application", "root": "", "sourceRoot": "src", "prefix": "app", "schematics": { "@schematics/angular:component": { "style": "scss" } }, "i18n": { "sourceLocale": "en", "locales": { "hu": { "translation": "src/locale/source.hu.json", "baseHref": "hu/" } } }, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "i18nMissingTranslation": "warning", "outputPath": "dist/projectname", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.app.json", "inlineStyleLanguage": "scss", "assets": ["src/favicon.ico", "src/assets"], "styles": ["src/scss/_styles.scss"] }, "configurations": { "production": { "aot": true, "buildOptimizer": true, "optimization": true, "budgets": [ { "type": "initial", "maximumWarning": "5mb", "maximumError": "6mb" }, { "type": "anyComponentStyle", "maximumWarning": "4kb", "maximumError": "8kb" } ], "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ] }, "development": { "buildOptimizer": false, "optimization": false, "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true, "index": "src/index.html" }, "localized": { "localize": ["hu", "en"] } }, "defaultConfiguration": "production" }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "configurations": { "production": { "browserTarget": "projectname:build:production" }, "development": { "browserTarget": "projectname:build:development" } }, "defaultConfiguration": "development" }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "projectname:build" } }, "test": { "builder": "@angular-devkit/build-angular:karma", "options": { "main": "src/test.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.spec.json", "karmaConfig": "karma.conf.js", "inlineStyleLanguage": "scss", "assets": ["src/favicon.ico", "src/assets"], "styles": ["src/scss/_styles.scss"] } } } } }, "cli": { "analytics": false } }
tsconfig.json
{ "compileOnSave": false, "compilerOptions": { "target": "es2022", "module": "esnext", "moduleResolution": "node", "lib": ["es2020", "dom"], "baseUrl": "./", "outDir": "./dist/out-tsc", "sourceMap": true, "forceConsistentCasingInFileNames": true, "strict": true, "strictNullChecks": false, "noImplicitAny": false, "noImplicitOverride": true, "noImplicitReturns": false, "noPropertyAccessFromIndexSignature": false, "noFallthroughCasesInSwitch": true, "declaration": false, "downlevelIteration": true, "experimentalDecorators": true, "importHelpers": true }, "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false, "strictInjectionParameters": true, "strictInputAccessModifiers": true, "strictTemplates": true, "strictPropertyInitialization": false } }
解决方案
1. 增加Buildx构建容器资源
Docker Buildx默认构建容器资源可能不足,导致Angular构建卡住,可手动指定CPU和内存配额:
docker buildx build --platform linux/amd64 --cpus 4 --memory 8g -t gcr.io/project_id/:latest -f Dockerfile.frontend . --push
2. 替换Node基础镜像
Alpine镜像使用musl libc,部分Node依赖存在兼容性问题,换用Debian系镜像:
FROM node:18-bullseye-slim as base WORKDIR /usr/src/app COPY package*.json ./ RUN npm install COPY . . RUN npm run build-prod
3. 查看详细构建日志
添加--progress=plain参数输出完整构建过程,定位卡住的具体步骤:
docker buildx build --platform linux/amd64 --progress=plain -t gcr.io/project_id/:latest -f Dockerfile.frontend . --push
4. 优化Dockerfile分层缓存
调整文件复制顺序,缓存依赖安装层,减少重复构建时间:
FROM node:18-bullseye-slim as base WORKDIR /usr/src/app # 先复制package文件,缓存依赖层 COPY package*.json ./ RUN npm ci --only=production && npm ci # 再复制源代码 COPY . . RUN npm run build-prod FROM nginx:alpine as runner COPY nginx.conf /etc/nginx/conf.d/default.conf COPY --from=base /usr/src/app/dist /usr/share/nginx/html/ EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
5. 禁用Angular并行构建
在angular.json的production配置中添加"parallel": false,避免多线程构建在容器中死锁:
"production": { // 原有配置... "parallel": false }
6. 改用Google Cloud Build构建
跳过本地Buildx,直接使用GCP的构建服务:
gcloud builds submit --tag gcr.io/project_id/latest --file Dockerfile.frontend .
内容的提问来源于stack exchange,提问作者aron bleier
相关产品推荐
相关产品推荐

