想要在java中或者其他方式访问dockerAPI都需要设置一个远程访问端口
vi /lib/systemd/system/docker.service
找到Execstart=/usr/bin/dockerd,并在后加上-H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock --insecure-registry=10.142.20.68 退出并且保存
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock --insecure-registry=10.142.20.68
运行以下命令,重启docker服务:
systemctl daemon-reload
service docker restart//重启启动docker
systemctl status docker//可以查看相关内容,看看2375是否已经设置好
运行:netstat -nlp |grep 2375 可以查看2375是否已经被监听
1. 编写上传附件接口或者从FTP下载附件至本地再上传
docker:
host: tcp://10.154.2.15:2375
registry:
project: osmcs
address: registry.paas
username: admin
password: 123456Dcos
@Value("${docker.host}")
private String dockerHost;//加载的IP
@Value("${docker.registry.project}")
private String registryProject;//harbor下的项目
@Value("${docker.registry.username}")
private String registryUserName;//harbor用户名
@Value("${docker.registry.password}")
private String registryPassword;//harbor密码
@Value("${docker.registry.address}")
private String registryAddress;//harbor的IP
@RequestMapping(value="/loadToRepository", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Object loadImageToRepository (@RequestPart(value = "file") MultipartFile file, String project, String softwareName, String version) {
System.out.println("DockerUtils loadImageToRepository begin");
System.out.println("docker镜像名称" + file.getOriginalFilename());
try {
String imageName = registryAddress + "/" + project + "/" + softwareName + ":" + version;
new UploadThread(registryAddress, dockerHost, registryUserName, registryPassword, imageName, file.getInputStream()).start();
} catch (IOException e) {
System.err.println("获取文件流失败");
}
return ResultUtil.success("上传结束,正在同步至镜像仓库");
}
从FTP下载附件至本地再上传至镜像仓库
@RequestMapping(value="/load", method = RequestMethod.POST)
public Object loadAndPushImage(@RequestBody Software software) {
System.out.println("DockerController load begin. request params are " + software);
System.out.println("dockerHost = " + dockerHost);
System.out.println("registryProject = " + registryProject);
System.out.println("registryUserName = " + registryUserName);
System.out.println("registryPassword = " + registryPassword);
System.out.println("registryAddress = " + registryAddress);
// String imageName = registryAddress + "/" + registryProject + "/" + softwareName + ":" + version;
String tempFilePath = null;
// if (!software.getFtpPath().startsWith(tempPath)) {
// return ResultUtil.success("这不是FTP上的文件");
// }
if (!tempPath.endsWith(File.separator)) {
tempFilePath = tempPath + File.separator + software.getFileName();
} else {
tempFilePath = tempPath + software.getFileName();
}
File tempFile = new File(tempFilePath);
OutputStream os = null;
try {
os = new FileOutputStream(tempFile);
ftpClient.retrieveFile(software.getFtpPath(), os);
os.flush();
os.close();
if (tempFile.exists()) {
String originalImageName = null;
if (registryAddress.endsWith("/")) {
originalImageName = registryAddress + registryProject + "/" + software.getSoftwareName().toLowerCase() + ":" + software.getVersion();
} else {
originalImageName = registryAddress + "/" + registryProject + "/" + software.getSoftwareName().toLowerCase() + ":" + software.getVersion();
}
String imageName = null;
//解压jar压缩文件
System.err.println("tempFilePath = " + tempFilePath);
if (tempFilePath.endsWith(".tar")) {
imageName = originalImageName;
originalImageName = UnCompress.getImageName(tempFilePath);
} else {
imageName = originalImageName;
}
System.out.println("originalImageName = " + originalImageName);
new UploadThread(registryAddress, dockerHost, registryUserName, registryPassword, originalImageName, imageName, new FileInputStream(tempFile)).start();
//删除文件
boolean delete = tempFile.delete();
System.out.println(delete ? "删除临时文件成功" : "删除临时文件失败");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("从FTP获取文件至本地失败" + e.getMessage());
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常" + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
System.out.println("关闭输出流失败" + e.getMessage());
}
}
}
return ResultUtil.success("上传结束,正在同步至镜像仓库");
}
2. 由于上传镜像比较慢,此处采用单独线程操作
public class UploadThread extends Thread {
private final static Logger logger = LoggerFactory.getLogger(UploadThread.class);
private String dockerHost;
private String registryAddress;
private String registryUserName;
private String registryPassword;
private InputStream inputStream;
private String originalImageName;
private String imageName;
public UploadThread(String registryAddress, String dockerHost, String registryUserName, String registryPassword,
String originalImageName, String imageName, InputStream inputStream) {
super();
this.originalImageName = originalImageName;
this.imageName = imageName;
this.dockerHost = dockerHost;
this.registryAddress = registryAddress;
this.registryUserName = registryUserName;
this.registryPassword = registryPassword;
this.inputStream = inputStream;
}
@Override
public void run() {
long beginTime = System.currentTimeMillis();
if (StringUtils.isEmpty(registryUserName)) {
registryUserName = null;
}
if (StringUtils.isEmpty(registryPassword)) {
registryPassword = null;
}
System.out.println("imageName = " + imageName);
System.out.println("dockerHost = " + dockerHost);
System.out.println("registryAddress = " + registryAddress);
System.out.println("registryUserName = " + registryUserName);
System.out.println("registryPassword = " + registryPassword);
AuthConfig authConfig = new AuthConfig()
.withUsername(registryUserName)
.withPassword(registryPassword)
.withRegistryAddress(registryAddress);
DockerClientConfig dockerClientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder()
.withDockerHost(dockerHost)
// .withDockerConfig("C:\\Users\\Administrator\\Desktop\\docker-java-api\\daemon.json")
.build();
DockerCmdExecFactory dockerCmdExecFactory = new JerseyDockerCmdExecFactory().withReadTimeout(60000)
.withConnectTimeout(1000)
.withMaxTotalConnections(100)
.withMaxPerRouteConnections(10);
DockerClient dockerClient = DockerClientBuilder.getInstance(dockerClientConfig)
.withDockerCmdExecFactory(dockerCmdExecFactory)
.build();
System.err.println("docker versin is " + dockerClient.versionCmd().exec().getVersion().toString());
try {
//加载镜像
LoadImageCmd loadImageCmd = dockerClient.loadImageCmd(inputStream);
loadImageCmd.exec();
//push至镜像仓库
PushImageResultCallback pushImageResultCallback = new PushImageResultCallback() {
@Override
public void onNext(PushResponseItem item) {
System.out.println("id:" + item.getId() +" status: "+item.getStatus());
super.onNext(item);
}
@Override
public void onComplete() {
System.out.println("Image pushed completed!");
super.onComplete();
}
};
if (!originalImageName.equalsIgnoreCase(imageName)) {
dockerClient.tagImageCmd(originalImageName, imageName, imageName.split(":")[1]).exec();
}
dockerClient.pushImageCmd(imageName)
.withAuthConfig(authConfig)
.exec(pushImageResultCallback)
.awaitSuccess();
System.out.println("push至docker镜像仓库后,删除本地load的镜像");
dockerClient.removeImageCmd(originalImageName).exec();
if (!originalImageName.equalsIgnoreCase(imageName)) {
dockerClient.removeImageCmd(imageName).exec();
}
System.out.println("本地镜像删除成功");
} catch (Exception e) {
e.printStackTrace();
logger.error("上传Docker镜像失败");
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
logger.error("文件流关闭失败");
}
}
}
// }
long endTime = System.currentTimeMillis();
System.out.println("上传Docker镜像结束,用时:" + (endTime - beginTime) + "ms");
}
}
3. 如果第三方接口想要调用此接口
public boolean uploadFile (String url, MultipartFile file, String tempPath) {
HttpHeaders headers = new HttpHeaders();
String tempFileName = UUID.randomUUID() + file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
logger.info("tempPath = " + tempPath);
String tempFilePath = tempPath + tempFileName;
File tempFile = new File(tempFilePath);
try {
file.transferTo(tempFile);
FileSystemResource fileSystemResource = new FileSystemResource(tempFilePath);
logger.info("临时文件路径:" + fileSystemResource.getPath());
MediaType type = MediaType.parseMediaType("multipart/form-data; charset=UTF-8");
headers.setContentType(type);
String cd = "filename=\"" + file.getOriginalFilename() + "\"";
headers.add("Content-Disposition", cd);
MultiValueMap form = new LinkedMultiValueMap();
form.add("file", fileSystemResource);
final RestTemplate restTemplate = new RestTemplate();
Object recv = restTemplate.postForEntity(url, form, Object.class);
try {
logger.info("调用上传镜像包接口返回的数据:" + recv.toString());
tempFile.delete();
} catch (Exception e) {
logger.error("删除本地临时文件失败", e);
}
} catch (IllegalStateException e) {
logger.error("httpclient close failed", e);
} catch (IOException e) {
logger.error("httpclient close failed", e);
}
return true;
}
4. 解压缩镜像包文件,获取镜像的标签内容(RepoTags),此处以解压tar文件为例
package com.github.dockerjava;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
/**
* 解压缩
* @author Administrator
*
*/
public class UnCompress {
private static final String BASE_DIR = "";
// 符号"/"用来作为目录标识判断符
private static final String PATH = File.separator;
private static final int BUFFER = 1024;
private static final String EXT = ".tar";
/**
* 归档
*
* @param srcPath
* @param destPath
* @throws Exception
*/
public static void archive(String srcPath, String destPath)
throws Exception {
File srcFile = new File(srcPath);
archive(srcFile, destPath);
}
/**
* 归档
*
* @param srcFile
* 源路径
* @param destPath
* 目标路径
* @throws Exception
*/
public static void archive(File srcFile, File destFile) throws Exception {
TarArchiveOutputStream taos = new TarArchiveOutputStream(
new FileOutputStream(destFile));
archive(srcFile, taos, BASE_DIR);
taos.flush();
taos.close();
}
/**
* 归档
*
* @param srcFile
* @throws Exception
*/
public static void archive(File srcFile) throws Exception {
String name = srcFile.getName();
String basePath = srcFile.getParent();
String destPath = basePath+File.separator + name + EXT;
archive(srcFile, destPath);
}
/**
* 归档文件
*
* @param srcFile
* @param destPath
* @throws Exception
*/
public static void archive(File srcFile, String destPath) throws Exception {
archive(srcFile, new File(destPath));
}
/**
* 归档
*
* @param srcPath
* @throws Exception
*/
public static void archive(String srcPath) throws Exception {
File srcFile = new File(srcPath);
archive(srcFile);
}
/**
* 归档
*
* @param srcFile
* 源路径
* @param taos
* TarArchiveOutputStream
* @param basePath
* 归档包内相对路径
* @throws Exception
*/
private static void archive(File srcFile, TarArchiveOutputStream taos,
String basePath) throws Exception {
if (srcFile.isDirectory()) {
archiveDir(srcFile, taos, basePath);
} else {
archiveFile(srcFile, taos, basePath);
}
}
/**
* 目录归档
*
* @param dir
* @param taos
* TarArchiveOutputStream
* @param basePath
* @throws Exception
*/
private static void archiveDir(File dir, TarArchiveOutputStream taos,
String basePath) throws Exception {
File[] files = dir.listFiles();
if (files.length < 1) {
TarArchiveEntry entry = new TarArchiveEntry(basePath
+ dir.getName() + PATH);
taos.putArchiveEntry(entry);
taos.closeArchiveEntry();
}
for (File file : files) {
// 递归归档
archive(file, taos, basePath + dir.getName() + PATH);
}
}
/**
* 数据归档
*
* @param data
* 待归档数据
* @param path
* 归档数据的当前路径
* @param name
* 归档文件名
* @param taos
* TarArchiveOutputStream
* @throws Exception
*/
private static void archiveFile(File file, TarArchiveOutputStream taos,
String dir) throws Exception {
/**
* 归档内文件名定义
*
*
* 如果有多级目录,那么这里就需要给出包含目录的文件名
* 如果用WinRAR打开归档包,中文名将显示为乱码
*
*/
TarArchiveEntry entry = new TarArchiveEntry(dir + file.getName());
//如果打包不需要文件夹,就用 new TarArchiveEntry(file.getName())
entry.setSize(file.length());
taos.putArchiveEntry(entry);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
file));
int count;
byte data[] = new byte[BUFFER];
while ((count = bis.read(data, 0, BUFFER)) != -1) {
taos.write(data, 0, count);
}
bis.close();
taos.closeArchiveEntry();
}
/**
* 解归档
*
* @param srcFile
* @throws Exception
*/
public static void dearchive(File srcFile) throws Exception {
String basePath = srcFile.getParent();
dearchive(srcFile, basePath);
}
/**
* 解归档
*
* @param srcFile
* @param destFile
* @throws Exception
*/
public static void dearchive(File srcFile, File destFile) throws Exception {
TarArchiveInputStream tais = new TarArchiveInputStream(
new FileInputStream(srcFile));
dearchive(destFile, tais);
tais.close();
}
/**
* 解归档
*
* @param srcFile
* @param destPath
* @throws Exception
*/
public static void dearchive(File srcFile, String destPath)
throws Exception {
dearchive(srcFile, new File(destPath));
}
/**
* 文件 解归档
*
* @param destFile
* 目标文件
* @param tais
* ZipInputStream
* @throws Exception
*/
private static void dearchive(File destFile, TarArchiveInputStream tais)
throws Exception {
TarArchiveEntry entry = null;
while ((entry = tais.getNextTarEntry()) != null) {
// 文件
String dir = destFile.getPath() + File.separator + entry.getName();
File dirFile = new File(dir);
// 文件检查
fileProber(dirFile);
if (entry.isDirectory()) {
dirFile.mkdirs();
} else {
dearchiveFile(dirFile, tais);
}
}
}
/**
* 文件 解归档
*
* @param srcPath
* 源文件路径
*
* @throws Exception
*/
public static void dearchive(String srcPath) throws Exception {
File srcFile = new File(srcPath);
dearchive(srcFile);
}
/**
* 文件 解归档
*
* @param srcPath
* 源文件路径
* @param destPath
* 目标文件路径
* @throws Exception
*/
public static void dearchive(String srcPath, String destPath)
throws Exception {
File srcFile = new File(srcPath);
dearchive(srcFile, destPath);
}
/**
* 文件解归档
*
* @param destFile
* 目标文件
* @param tais
* TarArchiveInputStream
* @throws Exception
*/
private static void dearchiveFile(File destFile, TarArchiveInputStream tais)
throws Exception {
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(destFile));
int count;
byte data[] = new byte[BUFFER];
while ((count = tais.read(data, 0, BUFFER)) != -1) {
bos.write(data, 0, count);
}
bos.close();
}
/**
* 文件探针
*
*
* 当父目录不存在时,创建目录!
*
*
* @param dirFile
*/
private static void fileProber(File dirFile) {
File parentFile = dirFile.getParentFile();
if (!parentFile.exists()) {
// 递归寻找上级目录
fileProber(parentFile);
parentFile.mkdir();
}
}
public static String getImageName(String tempFilePath) throws Exception{
System.out.println("tempFilePath = " + tempFilePath);
String dirPath = tempFilePath.substring(0, tempFilePath.lastIndexOf("."));
File dirFile = new File(dirPath);
if (!dirFile.exists()) {
dirFile.mkdirs();
}
UnCompress.dearchive(tempFilePath, dirPath);
if (!dirPath.endsWith(File.separator)) {
dirPath += File.separator;
}
//目标文件
String destFilePath = dirPath + "manifest.json";
File destFile = new File(destFilePath);
if (!destFile.exists()) {
return null;
}
StringBuilder sb = new StringBuilder("");
InputStream io = new FileInputStream(new File(destFilePath));
byte[] bytes = new byte[1024];
int len = 0;
while ((len = io.read(bytes)) > 0) {
sb.append(new String(bytes, 0, len));
}
String content = sb.toString();
//只取第一个配置项
List jsonList = (List) JSONArray.parse(content);
System.out.println("jsonList = " + jsonList);
return ((List)jsonList.get(0).get("RepoTags")).get(0);
/*if (content.startsWith("[")) {
content = content.substring(1, content.length() - 2);
}
System.out.println("content = " + content);
JSONObject json = JSONObject.parseObject(content.toString());
List list = (List) json.get("RepoTags");
System.out.println("list = " + list);
return list.get(0);*/
}
/*public static void main(String[] args) throws Exception {
String str = getImageName("E:\\temp\\osmcs_redis.tar");
System.err.println(str);
}*/
/*public static void main(String[] args) {
List jsonList = (List) JSONArray.parse("[{'Config':'05af71dd925161e515a980a129868929ee200bd5f896f6be61cf0a25fb5912df.json','RepoTags':['tomcat:latest'],'Layers':['cdc670427c7f26730bc075317993e7e72eea6df68e1be0ddf785cb3b774edc7c/layer.tar','5872a7aa42489b9517d31cc4ae83876cb38a21111acb0303a270ad6156c180f1/layer.tar','a34ac92b6f61c316eb200d74a3333c9f6fb24efdd15f2e1415474a9a96d0be62/layer.tar','0318148a6b1a640ef69623d9b97b59eed85285401e8250d71008e72f637cae31/layer.tar','86de30dac6602cac8b9b788a867daf10feaba9fd86f258a215e6396f34c94582/layer.tar','0a493e1fcea7fb5ecd1a72a3b5793ecf75de5af77e59280d4a54e0b01a5245cc/layer.tar','84421a45d2a124bd8817cbc127020e54ea805f77eb845174e1339d3d191c0f03/layer.tar','779b0e2cbb049d99e0802f5691bcd87c3ecf1d6c1469a9ddec2ff08522967672/layer.tar','87c68fcc6b34277e18005b0b436dc41064ca21db2337325ed75402d97a911a14/layer.tar','b5d3df54bc2ef8eaf83d2ea17e905821ba7fd186b2dbe4715e792cfc082dbeaa/layer.tar','617232c843330e0a4b9b2c7054188226497a5bc2338261bb23265de0c94d504e/layer.tar','75c4928affc72da624cbecc4b7d5b9896262d2e07cbbd13409b127f33c423cd8/layer.tar']},{'Config':'05a60462f8bafb215ddc5c20a364b5fb637670200a74a5bb13a1b23f64515561.json','RepoTags':['nginx:1.11.5'],'Layers':['3cae701620ae8eaf6a7f9988227eb21175b74f42e37a8187af521e0211555286/layer.tar','cb1fb070144286bf18e01b22d594e5e8eda2e5e39a28f5e1618105fee0e469e2/layer.tar','b52be048d4d2ebc586ef1134e94116a2189e36abe19975c650bb0b226c2ce81d/layer.tar']}]");
for (JSONObject jsonObject : jsonList) {
System.out.println(((List)jsonObject.get("RepoTags")).get(0));
}
}*/
}