我在 GitLab 设置中使用 Docker 运行程序来为我的应用程序测试构建 Docker 映像。该图像是一个带有一些预配置设置的 Keycloak 容器。
我创建了一个使用 Docker Compose 的
build.sh
脚本。我用 - ./data:/opt/keycloak/data/
挂载 Keycloak 数据目录。但是,当我启动容器时,容器因错误而崩溃。
build-keycloak-test-image:
stage: build-keycloak-test-image
before_script:
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
- apk add --no-cache curl
- chmod +x ./keycloak/test/build.sh
script:
- cd ./keycloak/test/
- sh ./build.sh
- docker push $KEYCLOAK_TEST_IMAGE
only:
- tags
#!/bin/bash
KEYCLOAK_URL="${KEYCLOAK_TEST_GEN_URL:-http://localhost:8889}"
# Endpoint to be checked
HEALTH_ENDPOINT="/health"
rm -fr ./data/*
mkdir ./data
chmod -R 777 ./data/
docker compose up -d
# ...
以下是启动容器后的一些日志:
2024-09-13 15:07:03,053 INFO [org.keycloak.common.Profile] (main) Preview features enabled: token-exchange
2024-09-13 15:07:12,589 INFO [io.quarkus.deployment.QuarkusAugmentor] (main) Quarkus augmentation completed in 10289ms
2024-09-13 15:07:13,837 INFO [org.keycloak.common.Profile] (main) Preview features enabled: token-exchange
2024-09-13 15:07:14,520 INFO [org.keycloak.quarkus.runtime.hostname.DefaultHostnameProvider] (main) Hostname settings: Base URL: <unset>, Hostname: <request>, Strict HTTPS: false, Path: <request>, Strict BackChannel: false, Admin URL: <unset>, Admin: <request>, Port: -1, Proxied: false
2024-09-13 15:07:17,244 WARN [io.quarkus.agroal.runtime.DataSources] (main) Datasource <default> enables XA but transaction recovery is not enabled. Please enable transaction recovery by setting quarkus.transaction-manager.enable-recovery=true, otherwise data may be lost if the application is terminated abruptly
2024-09-13 15:07:17,928 WARN [org.infinispan.PERSISTENCE] (keycloak-cache-init) ISPN000554: jboss-marshalling is deprecated and planned for removal
2024-09-13 15:07:17,966 WARN [org.infinispan.CONFIG] (keycloak-cache-init) ISPN000569: Unable to persist Infinispan internal caches as no global state enabled
2024-09-13 15:07:18,052 INFO [org.infinispan.CONTAINER] (keycloak-cache-init) ISPN000556: Starting user marshaller 'org.infinispan.jboss.marshalling.core.JBossUserMarshaller'
org.h2.message.DbException: Log file error: "/opt/keycloak/data/h2/keycloakdb.trace.db", cause: "org.h2.message.DbException: Error while creating file ""/opt/keycloak/data/h2"" [90062-224]" [90034-224]
org.h2.message.DbException: Log file error: "/opt/keycloak/data/h2/keycloakdb.trace.db", cause: "org.h2.message.DbException: Error while creating file ""/opt/keycloak/data/h2"" [90062-224]" [90034-224]
at org.h2.message.DbException.get(DbException.java:212)
at org.h2.message.TraceSystem.logWritingError(TraceSystem.java:327)
at org.h2.message.TraceSystem.openWriter(TraceSystem.java:348)
at org.h2.message.TraceSystem.writeFile(TraceSystem.java:296)
at org.h2.message.TraceSystem.write(TraceSystem.java:280)
at org.h2.message.Trace.error(Trace.java:187)
at org.h2.engine.Database.<init>(Database.java:397)
at org.h2.engine.Engine.openSession(Engine.java:92)
at org.h2.engine.Engine.openSession(Engine.java:222)
at org.h2.engine.Engine.createSession(Engine.java:201)
at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:343)
at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:125)
at org.h2.jdbcx.JdbcDataSource.getXAConnection(JdbcDataSource.java:322)
at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:232)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:536)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:517)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:75)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: Log file error: "/opt/keycloak/data/h2/keycloakdb.trace.db", cause: "org.h2.message.DbException: Error while creating file ""/opt/keycloak/data/h2"" [90062-224]" [90034-224]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:566)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
... 21 more
Caused by: org.h2.message.DbException: Error while creating file "/opt/keycloak/data/h2" [90062-224]
at org.h2.message.DbException.get(DbException.java:212)
at org.h2.store.fs.disk.FilePathDisk.createDirectory(FilePathDisk.java:391)
at org.h2.store.fs.FileUtils.createDirectory(FileUtils.java:85)
at org.h2.store.fs.FileUtils.createDirectories(FileUtils.java:382)
at org.h2.message.TraceSystem.openWriter(TraceSystem.java:338)
... 18 more
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: Error while creating file "/opt/keycloak/data/h2" [90062-224]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:566)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
... 23 more
Caused by: java.nio.file.AccessDeniedException: /opt/keycloak/data/h2
at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:90)
at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106)
at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
at java.base/sun.nio.fs.UnixFileSystemProvider.createDirectory(UnixFileSystemProvider.java:397)
at java.base/java.nio.file.Files.createDirectory(Files.java:700)
at org.h2.store.fs.disk.FilePathDisk.createDirectory(FilePathDisk.java:382)
... 21 more
2024-09-13 15:07:20,174 WARN [io.agroal.pool] (agroal-11) Datasource '<default>': Error while creating file "/opt/keycloak/data/h2" [90062-224]
2024-09-13 15:07:20,177 WARN [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator] (JPA Startup Thread) HHH000342: Could not obtain connection to query metadata: java.lang.NullPointerException: Cannot invoke "org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(java.sql.SQLException, String)" because the return value of "org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.sqlExceptionHelper()" is null
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.doTheWork(JtaIsolationDelegate.java:186)
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.lambda$delegateWork$1(JtaIsolationDelegate.java:75)
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.doInSuspendedTransaction(JtaIsolationDelegate.java:107)
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.delegateWork(JtaIsolationDelegate.java:72)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.getJdbcEnvironmentUsingJdbcMetadata(JdbcEnvironmentInitiator.java:279)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:193)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:69)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:119)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:264)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:239)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:216)
at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:52)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:125)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:248)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:216)
at org.hibernate.boot.internal.SessionFactoryOptionsBuilder.<init>(SessionFactoryOptionsBuilder.java:273)
at io.quarkus.hibernate.orm.runtime.recording.PrevalidatedQuarkusMetadata.buildSessionFactoryOptionsBuilder(PrevalidatedQuarkusMetadata.java:70)
at io.quarkus.hibernate.orm.runtime.boot.FastBootEntityManagerFactoryBuilder.build(FastBootEntityManagerFactoryBuilder.java:81)
at io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.createEntityManagerFactory(FastBootHibernatePersistenceProvider.java:74)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:80)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
at io.quarkus.hibernate.orm.runtime.JPAConfig$LazyPersistenceUnit.get(JPAConfig.java:156)
at io.quarkus.hibernate.orm.runtime.JPAConfig$1.run(JPAConfig.java:64)
at java.base/java.lang.Thread.run(Thread.java:840)
2024-09-13 15:07:21,152 INFO [org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory] (main) Node name: node_491456, Site name: null
org.h2.message.DbException: Log file error: "/opt/keycloak/data/h2/keycloakdb.trace.db", cause: "org.h2.message.DbException: Error while creating file ""/opt/keycloak/data/h2"" [90062-224]" [90034-224]
org.h2.message.DbException: Log file error: "/opt/keycloak/data/h2/keycloakdb.trace.db", cause: "org.h2.message.DbException: Error while creating file ""/opt/keycloak/data/h2"" [90062-224]" [90034-224]
at org.h2.message.DbException.get(DbException.java:212)
at org.h2.message.TraceSystem.logWritingError(TraceSystem.java:327)
at org.h2.message.TraceSystem.openWriter(TraceSystem.java:348)
at org.h2.message.TraceSystem.writeFile(TraceSystem.java:296)
at org.h2.message.TraceSystem.write(TraceSystem.java:280)
at org.h2.message.Trace.error(Trace.java:187)
at org.h2.engine.Database.<init>(Database.java:397)
at org.h2.engine.Engine.openSession(Engine.java:92)
at org.h2.engine.Engine.openSession(Engine.java:222)
at org.h2.engine.Engine.createSession(Engine.java:201)
at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:343)
at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:125)
at org.h2.jdbcx.JdbcDataSource.getXAConnection(JdbcDataSource.java:322)
at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:232)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:536)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:517)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:75)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: Log file error: "/opt/keycloak/data/h2/keycloakdb.trace.db", cause: "org.h2.message.DbException: Error while creating file ""/opt/keycloak/data/h2"" [90062-224]" [90034-224]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:566)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
... 21 more
Caused by: org.h2.message.DbException: Error while creating file "/opt/keycloak/data/h2" [90062-224]
at org.h2.message.DbException.get(DbException.java:212)
at org.h2.store.fs.disk.FilePathDisk.createDirectory(FilePathDisk.java:391)
at org.h2.store.fs.FileUtils.createDirectory(FileUtils.java:85)
at org.h2.store.fs.FileUtils.createDirectories(FileUtils.java:382)
at org.h2.message.TraceSystem.openWriter(TraceSystem.java:338)
... 18 more
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: Error while creating file "/opt/keycloak/data/h2" [90062-224]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:566)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
... 23 more
Caused by: java.nio.file.AccessDeniedException: /opt/keycloak/data/h2
at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:90)
at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106)
at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
at java.base/sun.nio.fs.UnixFileSystemProvider.createDirectory(UnixFileSystemProvider.java:397)
at java.base/java.nio.file.Files.createDirectory(Files.java:700)
at org.h2.store.fs.disk.FilePathDisk.createDirectory(FilePathDisk.java:382)
... 21 more
2024-09-13 15:07:23,831 WARN [io.agroal.pool] (agroal-11) Datasource '<default>': Error while creating file "/opt/keycloak/data/h2" [90062-224]
2024-09-13 15:07:23,908 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Failed to start server in (development) mode
2024-09-13 15:07:23,909 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Failed to obtain JDBC connection
2024-09-13 15:07:23,910 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Error while creating file "/opt/keycloak/data/h2" [90062-224]
2024-09-13 15:07:23,910 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: /opt/keycloak/data/h2
2024-09-13 15:07:23,912 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) For more details run the same command passing the '--verbose' option. Also you can use '--help' to see the details about the usage of the particular command.
services:
keycloak:
image: quay.io/keycloak/keycloak:23.0.6
ports:
- "8889:8080"
command:
- start-dev
volumes:
- ./data:/opt/keycloak/data/
environment:
KEYCLOAK_ADMIN: "admin"
KEYCLOAK_ADMIN_PASSWORD: "mypass"
KC_HEALTH_ENABLED: true
KC_METRICS_ENABLED: true
KC_HOSTNAME_STRICT: false
KC_HTTP_ENABLED: false
KC_FEATURES: "token-exchange"
PROXY_ADDRESS_FORWARDING: true
networks:
- gitlab
- default
networks:
gitlab:
name: gitlab-network
我的脚本应该创建数据目录并将权限设置为 777,因此任何进程都应该写入该目录。我检查了容器内部:
# ls /builds/dev/project/keycloak/test/ -lah
total 24K
drwxrwxrwx 3 root root 4.0K Sep 13 15:06 .
drwxrwxrwx 7 root root 4.0K Sep 4 12:56 ..
...
drwxrwxrwx 2 root root 4.0K Sep 13 15:06 data
在我的本地机器上一切正常,但容器在 GitLab 环境中失败。
有谁知道为什么 Docker 容器会因这些错误而崩溃?任何帮助将不胜感激!
T
此错误的原因是在运行的容器中当前用户是keyckloak:
uid=1000(keycloak) gid=0(root) groups=0(root)
但是目录
/opt/keycloak/data/
正在创建,但具有 root 限制并且没有组的写入权限:
drwxr-xr-x 2 root root 4.0K 10 月 31 日 19:21 /opt/keycloak/data/
您所做的权限检查 (
ls /builds/dev/project/keycloak/test/ -lah
) 显然不在容器内部,而是在 GitLab 工作的范围内(您在其中启动了 build.sh,为 ./data/ 目录提供了完全权限)。
要检查容器内的实际目录权限,您可以临时将 docker-compose 文件中的“command”指令替换为以下指令:
入口点:[“ls”,“-lshd”,“/opt/keycloak/data/”]
此处的解决方法之一可能是使当前用户成为容器内的 root,将
user: root
指令添加到 docker compose 文件中:
services:
keycloak:
image: quay.io/keycloak/keycloak:23.0.6
user: root
...
第二个选项是在 docker compose 中创建传递服务,该服务将为已安装的卷预先设置适当的所有者,如下所述:
或者最终构建一个扩展 keycloak 的自定义镜像,并在镜像构建阶段执行所有这些权限操作。