Ошибка сборки Soring boot & GRPC: program not found or is not executable
локальная сборка проходит (на mac)
на сервере (linux) ошибка
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':generateProto'.
> protoc: stdout: . stderr: oilmanager_v1.proto:3:1: warning: Import google/protobuf/empty.proto is unused.
oilmanager_v1.proto:2:1: warning: Import google/protobuf/timestamp.proto is unused.
/home/gradle/.gradle/caches/modules-2/files-2.1/io.grpc/protoc-gen-grpc-java/1.75.0/7dd0f4a0279b0babaa7c0e85690ad8de2ba636df/protoc-gen-grpc-java-1.75.0-linux-x86_64.exe: program not found or is not executable
Please specify a program using absolute path or make sure the program is available in your PATH system variable
--grpc_out: protoc-gen-grpc: Plugin failed with status code 1.
мой файл сборки
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.6'
id "io.freefair.lombok" version "8.4"
id 'org.hidetake.swagger.generator' version '2.19.2'
id 'jacoco'
id "org.sonarqube" version "5.1.0.4882"
id 'io.qameta.allure' version '2.12.0'
id 'com.google.osdetector' version '1.7.3'
id 'com.google.protobuf' version '0.9.4'
}
ext {
grpcVersion = '1.75.0'
protobufVersion = '3.25.8'
}
repositories {
maven {
name 'corp-mirror'
url "https://artifactory.ultimatec.ru/repository/maven-central/"
credentials {
username System.getenv('MAVEN_USERNAME') ?: "loader"
password System.getenv('MAVEN_PASSWORD') ?: "loader"
}
}
mavenCentral()
}
def grpcPluginCfg = configurations.detachedConfiguration(
dependencies.create("io.grpc:protoc-gen-grpc-java:${grpcVersion}:linux-x86_64@exe")
)
// не тянем transitives для exe
grpcPluginCfg.setTransitive(false)
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:${protobufVersion}"
}
plugins {
grpc {
// подставит нужный exe: osx-aarch_64 / osx-x86_64 / linux-x86_64 и т.д.
artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}:${osdetector.classifier}@exe"
}
}
generateProtoTasks {
all().configureEach {
plugins { grpc {} }
}
}
}
// гарантируем порядок: сначала proto -> потом compile
tasks.named('compileJava') {
dependsOn tasks.withType(com.google.protobuf.gradle.GenerateProtoTask)
}
group = 'ru.tms.project'
version = '7.18.0'
java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }
configurations { compileOnly { extendsFrom annotationProcessor } }
processResources { dependsOn(generateSwaggerCode) }
repositories {
mavenCentral()
maven {
name 'corp-mirror'
url "https://artifactory.ultimatec.ru/repository/maven-central/"
credentials {
username System.getenv('MAVEN_USERNAME') ?: "loader"
password System.getenv('MAVEN_PASSWORD') ?: "loader"
}
}
}
swaggerSources {
project {
inputFile = file("${rootDir}/src/main/resources/api/openApiModel.yaml")
inputFile = file("${rootDir}/src/main/resources/api/openApiEndpoint.yaml")
code {
language = 'spring'
configFile = file("${rootDir}/src/main/resources/api/config.json")
components = [models: true, apis: true, supportingFiles: 'ApiUtil.java']
dependsOn validation
}
}
}
compileJava.dependsOn swaggerSources.project.code
sourceSets.main.java.srcDir "${swaggerSources.project.code.outputDir}/src/main/java"
sourceSets.main.resources.srcDir "${swaggerSources.project.code.outputDir}/src/main/resources"
dependencyManagement {
imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:2023.0.1" }
}
dependencies {
implementation files('lib/api-lib-0.0.8.jar')
implementation 'org.springframework:spring-aspects'
implementation 'io.github.resilience4j:resilience4j-circuitbreaker'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.0'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.postgresql:postgresql:42.2.20'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-tracing'
implementation 'io.micrometer:micrometer-tracing-bridge-brave'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.mapstruct:mapstruct:1.6.0'
implementation 'io.micrometer:micrometer-registry-prometheus:1.13.3'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.1.3'
implementation 'com.zaxxer:HikariCP:5.1.0'
implementation 'org.jetbrains:annotations:24.1.0'
implementation 'org.liquibase:liquibase-core:4.29.2'
implementation 'io.github.resilience4j:resilience4j-spring-boot3:2.2.0'
implementation 'org.springframework.retry:spring-retry'
// gRPC / Protobuf runtime
implementation "io.grpc:grpc-netty-shaded:${grpcVersion}"
implementation "io.grpc:grpc-protobuf:${grpcVersion}"
implementation "io.grpc:grpc-stub:${grpcVersion}"
implementation "com.google.protobuf:protobuf-java:${protobufVersion}"
compileOnly "jakarta.annotation:jakarta.annotation-api:2.1.1"
compileOnly "javax.annotation:javax.annotation-api:1.3.2"
testCompileOnly "javax.annotation:javax.annotation-api:1.3.2"
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.cloud:spring-cloud-starter'
implementation 'org.springframework.cloud:spring-cloud-commons:4.1.1'
implementation 'org.springframework.boot:spring-boot-starter-logging'
implementation 'io.github.resilience4j:resilience4j-timelimiter:2.1.0'
implementation 'io.github.resilience4j:resilience4j-retry:2.1.0'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.3'
swaggerCodegen 'org.openapitools:openapi-generator-cli:7.3.0'
implementation 'io.swagger.core.v3:swagger-annotations:2.2.20'
runtimeOnly 'org.postgresql:postgresql'
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-fabric8:3.1.3'
implementation 'org.springframework.cloud:spring-cloud-starter-loadbalancer'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
compileOnly "org.projectlombok:lombok"
annotationProcessor "org.projectlombok:lombok"
implementation 'com.fasterxml.jackson.core:jackson-annotations'
implementation 'com.fasterxml.jackson.core:jackson-core'
annotationProcessor "org.mapstruct:mapstruct-processor:1.6.0"
testImplementation 'com.opentable.components:otj-pg-embedded:1.1.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
testImplementation 'org.mockito:mockito-core:5.5.0'
testImplementation 'org.mockito:mockito-inline:5.2.0'
}
tasks.named('test') {
useJUnitPlatform()
jvmArgs '-XX:+EnableDynamicAgentLoading'
jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
finalizedBy jacocoTestReport
}
test { jvmArgs '-XX:+EnableDynamicAgentLoading' }
springBoot { mainClass = "ru.tms.project.ProjectServiceApplication" }
jacoco { toolVersion = "0.8.12" }
jacocoTestReport {
dependsOn test
reports { xml.required = true; csv.required = false; html.required = true }
}
sourceSets {
main {
proto { srcDir 'src/main/resources/proto' }
java {
srcDirs += ["${buildDir}/generated/source/proto/main/java",
"${buildDir}/generated/source/proto/main/grpc"]
}
}
}
sonar {
properties {
property "sonar.projectKey", "project-service"
property "sonar.projectName", "project-service"
property "sonar.qualitygate.wait", true
property "sonar.java.coveragePlugin", "jacoco"
property "sonar.coverage.exclusions",
" **/dto/**," + " **/config/**," + " **/model/**," + " **/mapper/**," + " **/exception/**," + " **/redis/**," + " **/*Application.java," + " **/*Time.java," + " **/*Controller.java"
property "sonar.test.exclusions", "**/*"
}
}
докер
FROM gradle:8.8-jdk21 AS build
USER gradle
WORKDIR /home/gradle/app
ENV GRADLE_USER_HOME=/home/gradle/.gradle
COPY --chown=gradle:gradle gradlew gradlew.bat gradle /home/gradle/app/
COPY --chown=gradle:gradle build.gradle settings.gradle /home/gradle/app/
COPY --chown=gradle:gradle lib /home/gradle/app/lib
COPY --chown=gradle:gradle src /home/gradle/app/src
RUN chmod +x ./gradlew
# выкинуть ранее стянутый native-плагин
RUN rm -rf "$GRADLE_USER_HOME/caches/modules-2/files-2.1/io.grpc/protoc-gen-grpc-java" || true
# сразу сборка с обновлением зависимостей
RUN ./gradlew --no-daemon clean generateProto bootJar --refresh-dependencies
FROM openjdk:21-jdk-slim
ENV APP_HOME=/opt/app
ENV JAR_NAME=project-service.jar
WORKDIR $APP_HOME
COPY --from=build /home/gradle/app/build/libs/*.jar ./$JAR_NAME
ENV TZ=Europe/Moscow
EXPOSE 5008
ENTRYPOINT ["java","-Duser.timezone=Europe/Moscow","-jar","./project-service.jar"]