如何在GitLab CI的dock:dind中执行卷映射(装入卷)? [英] How can I do volume mapping (mounting volumes) in dock:dind in GitLab CI?
本文介绍了如何在GitLab CI的dock:dind中执行卷映射(装入卷)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
测试脚本:
package seleniumTest;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class LoginTest_chrome_ci {
WebDriver driver;
File folder;
@BeforeMethod
public void setUp() throws MalformedURLException {
String directory = "/target";
folder = new File(directory);
System.setProperty("webdriver.chrome.driver", "chromedriver.exe");
ChromeOptions options = new ChromeOptions();
Map<String, Object> prefs = new HashMap<String, Object>();
prefs.put("profile.default_content_settings.popups", 0);
prefs.put("download.prompt_for_download", "false");
prefs.put("download.directory_upgrade", "true");
prefs.put("download.default_directory", folder.getAbsolutePath());
options.setExperimentalOption("prefs", prefs);
DesiredCapabilities cap = new DesiredCapabilities();
cap.setBrowserName("chrome");
cap.setCapability(ChromeOptions.CAPABILITY, options);
driver = new RemoteWebDriver(new URL("http://docker:4444/wd/hub"), cap);
}
@AfterMethod
public void tearDown() {
driver.quit();
}
@Test
public void downloadFileTest() throws InterruptedException {
driver.get("http://the-internet.herokuapp.com/download");
driver.findElement(By.linkText("some-file.txt")).click();
Thread.sleep(4000);
File listOffFiles[] = folder.listFiles();
System.out.println(listOffFiles.length);
Assert.assertTrue(listOffFiles.length > 0);
for(File file : listOffFiles) {
Assert.assertTrue(file.length() > 0);
}
}
}
在docker-compose文件中,我已经完成了Chrome容器的卷映射:
version: "3"
services:
chrome:
image: selenium/node-chrome:4.0.0-20211013
container_name: chrome
shm_size: 2gb
depends_on:
- selenium-hub
volumes:
- /target:/home/seluser/Downloads
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
- SE_NODE_GRID_URL=http://localhost:4444
ports:
- "6900:5900"
selenium-hub:
image: selenium/hub:4.0.0-20211013
container_name: selenium-hub
ports:
- "4442:4442"
- "4443:4443"
- "4444:4444"
我使用的gitlab-ci.yml文件是:
image: adoptopenjdk/openjdk11
stages:
- gradle-build
- docker-test
.gradle_template: &gradle_definition
variables:
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
before_script:
- export GRADLE_USER_HOME=${CI_PROJECT_DIR}/.gradle
gradle-build:
<<: *gradle_definition
stage: gradle-build
script:
- chmod +x ./gradlew
- ./gradlew --build-cache assemble
cache:
key: "$CI_COMMIT_REF_NAME"
paths:
- build
- .gradle
artifacts:
paths:
- build/libs/*.jar
expire_in: 1 day
only:
- feature/multi-browsers
chrome-test:
stage: docker-test
image:
name: docker/compose:1.29.2
entrypoint: [ "/bin/sh", "-c" ]
services:
- docker:19.03.12-dind
variables:
DOCKER_TLS_CERTDIR: ""
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2375/
cache:
key: "$CI_COMMIT_REF_NAME"
policy: pull
paths:
- build
- .gradle
dependencies:
- gradle-build
before_script:
- docker info
- docker-compose --version
script:
- apk add --no-cache docker-compose
- apk add openjdk11
- mkdir /target
- chmod -R 777 /target
- docker-compose down
- docker-compose up --build --force-recreate --no-deps -d
- echo "Hello, chrome-test"
- chmod +x ./gradlew
- ./gradlew :test --tests "LoginTest_chrome_ci"
artifacts:
when: always
reports:
junit: build/test-results/test/**/TEST-*.xml
paths:
- build/reports/*
expire_in: 1 day
only:
- feature/multi-browsers
after_script:
- echo "End CI"
我收到的错误是:
Gradle suite > Gradle test > seleniumTest.LoginTest_chrome_ci > downloadFileTest FAILED
java.lang.AssertionError at LoginTest_chrome_ci.java:71
推荐答案
使用docker:dind
服务时,带有docker-compose的卷映射或多或少会正常工作。
./target
而不是/target
。
使用docker挂载目录:dind
作为可重现的最小示例:
获取以下合成文件:
version: "3"
services:
test:
image: busybox
entrypoint: ["/bin/sh", "-c", "echo hello > /opt/data/foo.txt"]
volumes:
- ./target:/opt/data
这将创建单个容器,其装入点位于相对目录./target
,并将其装入到容器中的/opt/data
。
当服务容器启动时,它只会创建一个文本为hello
的文件/opt/data/foo.txt
。
和以下GitLab CI YAML:
test:
image: docker/compose
services:
- docker:dind
script:
- ls # no target directory exists
- docker-compose up
- ls target # target directory was created and foo.txt exists
- cat ./target/foo.txt # see the contents of foo.txt as "hello"
因此,您的错误一定是由于装入点未装入目录以外的其他原因造成的。
权限注意事项
文件/目录权限仍然适用于绑定装载。因此,容器中的用户需要拥有对挂载的目录/文件进行读/写的权限。您在这种情况下几乎肯定会遇到的问题是selenium/node-chrome:4.0.0-20211013
停靠容器中的用户的UID/GID为1200
/1201
。因此,docker-compose
在您的作业中为卷装载创建的目录将不会被容器中的用户写入。
例如,上面的相同最小示例--如果将映像从busybox
(以root身份运行,与作业容器相同)更改为selenium/node-chrome:4.0.0-20211013
,使用不同的用户UID/GID运行,则作业将失败,并显示";权限被拒绝";错误。
因此,可以得出结论,您的问题是Chrome无法写入~/Downloads
目录,这就是您在下载目录中看不到文件的原因。
如何解决问题
若要解决此问题,应提前chown
将挂载点创建到容器中用户的uid/gid。
所以有两件事:
- 将目录更改为
./target
,而不是/target
(更新合成文件和代码) - 在您的GitLab-CI作业中,请在启动docker-compose之前预先创建
./target
和chown 1200:1201 ./target
类似以下内容将解决权限问题:
before_script:
- mkdir -p ./target
- chown 1200:1201 ./target
这篇关于如何在GitLab CI的dock:dind中执行卷映射(装入卷)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文