在 docker compose 上执行 SQL 脚本

Posted

技术标签:

【中文标题】在 docker compose 上执行 SQL 脚本【英文标题】:Execute SQL script on docker compose 【发布时间】:2020-01-27 07:26:57 【问题描述】:

我有一个项目,当 ./entrypoint.sh 或 docker-compose up 从项目的根目录运行并生成 swagger API 接口时运行,但调用返回入口响应没有数据。

如果我在没有 docker 的情况下在 localhost 上使用 mysql 运行,则效果很好。如何加载数据?

入口点.sh

#!/bin/bash

docker network create turingmysql
docker container run -p  3306:3306 --name mysqldb --network turingmysql -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=tshirtshop -d mysql:5.7
docker-compose build
docker-compose up

Docker 文件

FROM mysql:5.7

ADD ./database/tshirtshop.sql /docker-entrypoint-initdb.d
#### Stage 1: Build the application
FROM openjdk:8-jdk-alpine as build

# Set the current working directory inside the image
WORKDIR /app

# Copy maven executable to the image
COPY mvnw .
COPY .mvn .mvn

# Copy the pom.xml file
COPY pom.xml .

# Build all the dependencies in preparation to go offline. 
# This is a separate step so the dependencies will be cached unless 
# the pom.xml file has changed.
RUN ./mvnw dependency:go-offline -B

# Copy the project source
COPY src src


# Package the application
RUN ./mvnw package -DskipTests
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)

#### Stage 2: A minimal docker image with command to run the app 
FROM openjdk:8-jre-alpine

ARG DEPENDENCY=/app/target/dependency

# Copy project dependencies from the build stage
COPY --from=build $DEPENDENCY/BOOT-INF/lib /app/lib
COPY --from=build $DEPENDENCY/META-INF /app/META-INF
COPY --from=build $DEPENDENCY/BOOT-INF/classes /app

ENTRYPOINT ["java","-cp","app:app/lib/*","com.turing.ecommerce.TuringApplication"]

docker-compose.yml

version: '3.7'

# Define services
services:
  # App backend service
  app-server:
    # Configuration for building the docker image for the backend service
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080" # Forward the exposed port 8080 on the container to port 8080 on the host machine
    restart: always
    depends_on: 
      - mysqldb # This service depends on mysql. Start that first.
    environment: # Pass environment variables to the service
      SPRING_DATASOURCE_URL: jdbc:mysql://mysqldb:3306/tshirtshop?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: root   
    networks: # Networks to join (Services on the same network can communicate with each other using their name)
      - turingmysql

      # Database Service (Mysql)
  mysqldb:
    image: mysql:5.7
    ports:
      - "3306:3306"
    restart: always

    environment:
      MYSQL_DATABASE: tshirtshop
      MYSQL_USER: root
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - db-data:/var/lib/mysql

    networks:
      - turingmysql  


# Volumes
volumes:
  db-data:

# Networks to be created to facilitate communication between containers
networks:
  turingmysql:

【问题讨论】:

那么,tshirtshop.sql 是否将任何值插入数据库?您的应用程序是否正确配置为查询数据库而不返回空结果? 是的,很多创建表和插入语句。 您是否在 API 中插入了日志语句以验证应该返回的内容? 如果我在没有 docker 的情况下运行,API 调用会返回数据。我已经部署在heroku 上,我在其中单独创建了数据库并进行了部署,它可以工作,但我需要对其进行 docker 化。 【参考方案1】:

感谢cricket_007 和Adii 的回复。他们把我引向了正确的方向。我想记录我的经验以及问题是如何解决的。码头化的新手,所以我是通过实践来学习的。对于任何刚接触 dockerization 并在 Spring Boot、MySQL 和 docker 中遇到相同问题的人,这肯定会有所帮助

首先,我的 entrypoint.sh 在下面发生了变化。 docker-compose down 用于重启。

     #!/bin/bash

docker-compose down -v
docker-compose up --build

其次,我不得不使用现有的 mysql 映像而不是构建一个。

version: '3.7'

# Define services
services:
  # App backend service
  app-server:
    # Configuration for building the docker image for the backend service
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080" # Forward the exposed port 8080 on the container to port 8080 on the host machine
    restart: always
    depends_on: 
      - mysql # This service depends on mysql. Start that first.
    environment: # Pass environment variables to the service
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/tshirtshop?useSSL=false&allowPublicKeyRetrieval=true&useLegacyDatetimeCode=false&serverTimezone=UTC
      SPRING_DATASOURCE_USERNAME: turing
      SPRING_DATASOURCE_PASSWORD: pass  
    networks: # Networks to join (Services on the same network can communicate with each other using their name)
      - turingmysql

      # Database Service (Mysql)
  mysql:
    image: mysql/mysql-server
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: tshirtshop
      MYSQL_USER: turing
      MYSQL_PASSWORD: pass


    volumes:
      - db-data:/var/lib/mysql
      - ./database:/docker-entrypoint-initdb.d
    tty: true
    networks: # Networks to join (Services on the same network can communicate with each other using their name)
      - turingmysql

# Volumes
volumes:
  db-data:

 # Networks to be created to facilitate communication between containers
networks:
  turingmysql:
    driver: bridge

需要指定网络是一个网桥。我的 sql 文件是从相对于 docker-compose.yml 的文件夹安装的。还必须将 allowPublicKeyRetrieval=true 添加到我的 jdbc url。创建了一个用户来访问数据库 tshirtshop。

这里是 Dockerfile。

#### Stage 1: Build the application
FROM openjdk:8-jdk-alpine as build

# Set the current working directory inside the image
WORKDIR /app

# Copy maven executable to the image
COPY mvnw .
COPY .mvn .mvn

# Copy the pom.xml file
COPY pom.xml .

# Build all the dependencies in preparation to go offline. 
# This is a separate step so the dependencies will be cached unless 
# the pom.xml file has changed.
RUN ./mvnw dependency:go-offline -B

# Copy the project source
COPY src src


# Package the application
RUN ./mvnw package -DskipTests
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)

#### Stage 2: A minimal docker image with command to run the app 
FROM openjdk:8-jre-alpine

ARG DEPENDENCY=/app/target/dependency

# Copy project dependencies from the build stage
COPY --from=build $DEPENDENCY/BOOT-INF/lib /app/lib
COPY --from=build $DEPENDENCY/META-INF /app/META-INF
COPY --from=build $DEPENDENCY/BOOT-INF/classes /app

ENTRYPOINT ["java","-cp","app:app/lib/*","com.turing.ecommerce.TuringApplication"]

运行,从项目的根目录 ./entrypoint.sh 在 mac 上,其余的都是历史。

【讨论】:

【参考方案2】:

你有两个 Dockerfile 吗?看起来您构建了自己的 MySQL 容器?

否则,这些不应该是您的 Java 多阶段构建的一部分

FROM mysql:5.7

ADD ./database/tshirtshop.sql /docker-entrypoint-initdb.d

假设您确实为 mysql 构建了一个单独的映像,在 Docker-Compose 中,您没有使用它,因为您仍然指的是image: mysql:5.7

与其自己构建,不如将 SQL 脚本挂载到其中

例如

  mysqldb:
    image: mysql:5.7
    ...
    volumes:
      - db-data:/var/lib/mysql
      - ./database/tshirtshop.sql:/docker-entrypoint-initdb.d/0_init.sql

然后,暂时忘记 Java 服务并使用 MySQL 工作台或 mysql CLI 来验证数据是否确实存在。完成后,启动 API

【讨论】:

我只有一个 dockerfile。我已经删除了这两行并尝试安装,没有喘息的机会。 如果你做docker-compose logs mysqldb,你看到它运行脚本了吗? docker-compose rm -sf mysqldb,然后重新启动 另外,您应该从脚本中删除 docker container run,因为您是在 docker-compose up 命令中启动 mysql【参考方案3】:

如果您已经将sql scipt 复制到 docker build,那么您不需要在 docker-compose 中再次映射它,如果您有 docker-compose,那么您不会使用 bash 脚本单个命令 docker-compose up --build 来执行工作。

所以根据你的 Dockerfile 修改你的 docker-compose。

Dockerfile

FROM mysql

ADD init.sql /docker-entrypoint-initdb.d

码头工人撰写

version: '3.7'

services:
  # App backend service
  app-server:
    # Configuration for building the docker image for the backend service
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080" # Forward the exposed port 8080 on the container to port 8080 on the host machine
    restart: always
    depends_on: 
      - mysqldb # This service depends on mysql. Start that first.
    environment: # Pass environment variables to the service
      SPRING_DATASOURCE_URL: jdbc:mysql://mysqldb:3306/tshirtshop?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: root   
    networks: # Networks to join (Services on the same network can communicate with each other using container name)
      - uringmysql

      # Database Service (Mysql)

  mysql:
    build: .
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: appdata
      MYSQL_USER: test
      MYSQL_PASSWORD: root123
    volumes:
      - db-data:/var/lib/mysql
    tty: true
# Volumes
volumes:
  db-data:

# Networks to be created to facilitate communication between containers
networks:
  turingmysql:

现在运行

docker-compose up --build

这将构建和构建容器,您不需要映射主机初始化脚本,因为它已经在 Docker 映像中。

目录结构如下所示

现在您的应用程序将能够使用jdbc:mysql://mysqldb:3306/tshirtshop? 这个端点访问数据库,因为两者都在同一个网络中,并且可以使用名称相互引用。

【讨论】:

以上是关于在 docker compose 上执行 SQL 脚本的主要内容,如果未能解决你的问题,请参考以下文章

docker-compose mysql init sql 未执行

Docker-compose mysql:导入 .sql

Docker compose安装Elasticsearch

Docker-compose 与 H2 docker 数据库的 setup.sql 文件

在 AWS ECS 上使用 docker-compose 进行持续部署的最佳实践

docker-compose部署nacos单机版(简洁优化版)