本地Spring/MySQL应用Docker Compose部署Azure遇阻求助
背景
本地可正常运行的Spring/MySQL应用,使用docker-compose部署到Azure容器实例(ACI)时遇到一系列问题,初始docker-compose配置如下:
version: '3.7' services: app-server: build: context: . dockerfile: Dockerfile ports: - "8080:8080" depends_on: - db environment: SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/shapeshop?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false SPRING_DATASOURCE_USERNAME: root SPRING_DATASOURCE_PASSWORD: root networks: - backend db: image: mysql:5.7 ports: - "3306:3306" restart: always environment: MYSQL_DATABASE: shapeshop MYSQL_USER: admin MYSQL_PASSWORD: admin MYSQL_ROOT_PASSWORD: root volumes: - "db-data2:/var/lib/mysql" - "./SCHEMA.sql:/docker-entrypoint-initdb.d/SCHEMA.sql" - "./TEST_DATA.sql:/docker-entrypoint-initdb.d/TEST_DATA.sql" networks: - backend volumes: db-data2: networks: backend:
操作步骤与报错
- 切换到ACI上下文:
docker context use myacicontext
- 执行部署命令:
docker compose up
- 首次报错:
cannot use ACI volume, required driver is "azure_file", found ""
- 调整volumes配置(已提前创建
shapeshopstorageaccount存储账户和shapeshopfileshare文件共享):
volumes: db-data2: driver: azure_file driver_opts: share_name: shapeshopfileshare storage_account_name: shapeshopstorageaccount
此时又报错:
The storage account named shapeshopstorageaccount is already taken.
- 接着遇到主机路径不允许的错误:
host path ("C:\dev\shape-shop-back-end\SCHEMA.sql") not allowed as volume source, you need to reference an Azure File Share defined in the 'volumes' section
- 修改db服务的volumes配置后:
db: image: mysql:5.7 ports: - "3306:3306" restart: always environment: MYSQL_DATABASE: shapeshop MYSQL_USER: admin MYSQL_PASSWORD: admin MYSQL_ROOT_PASSWORD: root volumes: - "db-data2:/var/lib/mysql" - "db-data2:/SCHEMA.sql" - "db-data2:/TEST_DATA.sql"
出现新错误:
containerinstance.ContainerGroupsClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="InvalidContainerImage" Message="The image cannot be empty for container 'app-server' in container group 'shape-shop-back-end'."
用户疑问
- 为何会出现镜像为空的错误?本地构建的app-server镜像,docker-compose难道不会自动构建并推送吗?是否需要指定镜像的推送位置?
- db服务的volumes条目具体含义是什么?第一行
db-data2:/var/lib/mysql应该是指定数据库数据存储位置,但原来的两行本地SQL文件是用来初始化数据库的,仅在MySQL启动时运行一次,docker-entrypoint-initdb.d是容器内的路径吗?如何让这两个SQL文件作用于MySQL容器?
解决方案
问题1:镜像为空错误的原因与解决
ACI无法直接使用本地构建的镜像,必须将镜像推送到**Azure容器注册表(ACR)**或者其他公开镜像仓库。docker-compose在ACI上下文中不会自动构建并推送本地镜像,需要手动完成:
- 在Azure上创建ACR实例
- 登录ACR:
docker login <acr-name>.azurecr.io - 构建本地镜像并标记ACR地址:
docker build -t <acr-name>.azurecr.io/app-server:v1 . - 推送镜像到ACR:
docker push <acr-name>.azurecr.io/app-server:v1 - 修改docker-compose中app-server的配置,替换build为image字段:
app-server: image: <acr-name>.azurecr.io/app-server:v1 ports: - "8080:8080" depends_on: - db environment: SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/shapeshop?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false SPRING_DATASOURCE_USERNAME: root SPRING_DATASOURCE_PASSWORD: root networks: - backend
问题2:存储账户重复错误
是的,当你在docker-compose中配置azure_file驱动的volume时,如果指定的storage_account_name不存在,docker会尝试自动创建;但如果账户已存在,就会报错。只需确保配置的storage_account_name是你已创建的正确名称即可,不需要修改配置,直接重新部署。
问题3:SQL初始化文件的处理
ACI不允许使用本地主机路径作为volume源,所以需要将SQL文件上传到Azure文件共享,然后挂载到MySQL容器的/docker-entrypoint-initdb.d目录(这个路径是MySQL容器内部的初始化脚本目录,容器启动时会自动执行该目录下的.sql文件):
- 将本地的
SCHEMA.sql和TEST_DATA.sql上传到shapeshopfileshare文件共享中 - 修改db服务的volumes配置,将文件共享挂载到容器的初始化目录:
db: image: mysql:5.7 ports: - "3306:3306" restart: always environment: MYSQL_DATABASE: shapeshop MYSQL_USER: admin MYSQL_PASSWORD: admin MYSQL_ROOT_PASSWORD: root volumes: - "db-data2:/var/lib/mysql" - "db-data2:/docker-entrypoint-initdb.d/" networks: - backend
注意:挂载整个目录到
/docker-entrypoint-initdb.d/后,MySQL启动时会自动执行该目录下的所有.sql文件,无需单独挂载每个文件。
最终完整docker-compose配置
version: '3.7' services: app-server: image: <acr-name>.azurecr.io/app-server:v1 ports: - "8080:8080" depends_on: - db environment: SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/shapeshop?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false SPRING_DATASOURCE_USERNAME: root SPRING_DATASOURCE_PASSWORD: root networks: - backend db: image: mysql:5.7 ports: - "3306:3306" restart: always environment: MYSQL_DATABASE: shapeshop MYSQL_USER: admin MYSQL_PASSWORD: admin MYSQL_ROOT_PASSWORD: root volumes: - "db-data2:/var/lib/mysql" - "db-data2:/docker-entrypoint-initdb.d/" networks: - backend volumes: db-data2: driver: azure_file driver_opts: share_name: shapeshopfileshare storage_account_name: shapeshopstorageaccount networks: backend:
内容的提问来源于stack exchange,提问作者Oliver Watkins

