山东大学软件学院项目实训-创新实训-山大软院网络攻防靶场实验平台(五)-docker容器的动态管理

目录

  • 前言:
  • 一、搭建测试环境
  • 二、编写测试代码-动态创建容器
    • 1、编写配置文件 pom.xml 与 application.yaml
    • 2、编写 indexController
    • 3、编写 DockerClientUtils
    • 4、编写前端界面
  • 三、编写测试代码-模拟题目环境
  • 四、打包、部署、测试
    • 1、服务器 docker 配置
    • 2、腾讯云防火墙端口
    • 3、dockerfile 编写
  • 4、镜像生成
    • 5、运行测试


前言:

前面的几天时间里,学习了 docker 的安装与使用,学会使用命令行控制 docker 容器的创建、删除等。然后学习了 springboot 框架的基本使用、了解其框架基本原理与运行机制。完成了这些准备后,接下来我主要面临的一个比较关键的技术难点是如何使用 springboot 连接远程服务器上 docker 服务,实现容器的动态创建与删除。如果实现了这个技术点,那么我们的靶场题目环境便可以打包成镜像,然后放到服务器中,通过动态的创建、删除容器,来实现题目环境的部署。



一、搭建测试环境

后端动态创建容器使用 springboot 框架搭建
山东大学软件学院项目实训-创新实训-山大软院网络攻防靶场实验平台(五)-docker容器的动态管理_第1张图片

模拟靶场环境使用 springboot 框架。
山东大学软件学院项目实训-创新实训-山大软院网络攻防靶场实验平台(五)-docker容器的动态管理_第2张图片

前端就简单使用 HTML 写一个测试页面即可。
在这里插入图片描述



二、编写测试代码-动态创建容器

1、编写配置文件 pom.xml 与 application.yaml

pom.xml 导入项目需要用到的相关依赖


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.6.4version>
        <relativePath/> 
    parent>
    <groupId>com.examplegroupId>
    <artifactId>SDU_SpringBoot_fontartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>SDU_SpringBoot_fontname>
    <description>SDU_SpringBoot_fontdescription>
    <properties>
        <java.version>1.8java.version>
    properties>
    <dependencies>
        
        
        <dependency>
            <groupId>com.github.docker-javagroupId>
            <artifactId>docker-javaartifactId>
            <version>3.1.5version>
        dependency>

        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>fastjsonartifactId>
            <version>1.2.28version>
        dependency>
        

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starterartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
            
            <exclusions>
                <exclusion>
                    <groupId>org.slf4jgroupId>
                    <artifactId>slf4j-log4j12artifactId>
                exclusion>
            exclusions>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-thymeleafartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>

            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintagegroupId>
                    <artifactId>junit-vintage-enginaartifactId>
                exclusion>
            exclusions>
        dependency>

        
        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>javax.servlet-apiartifactId>
            <scope>providedscope>
        dependency>
        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>jstlartifactId>
        dependency>

        
        <dependency>
            <groupId>org.apache.tomcat.embedgroupId>
            <artifactId>tomcat-embed-jasperartifactId>
            <scope>providedscope>
        dependency>


    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>

project>

application.yaml 对项目进行配置,配置一下 html 文件的匹配路径

spring:
  thymeleaf:
    prefix:
      classpath: /templates/

2、编写 indexController

用于 index 页面的匹配
实现浏览器请求 “/” 或 “/index.html” 时,匹配到 index.html 页面。

package com.example.sdu_springboot_font.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Controller
public class indexController {
    @RequestMapping(value={"/","/index.html"})
    public String index(){
        return "index";
    }
}

接下来是比较重要的部分,即 java 远程操控服务器上的 docker 服务,实现容器的创建、删除等基本操作。在思考如何实现这个功能的时候,查看了大量的文章,在网上搜索了很多的相关博客,也简单看了一下几篇关于 docker 在 CTF 比赛中容器创建的相关应用的论文。经过尝试,最后使用 docker-java 成功实现该功能。

docker-java 简介:
docker-java 是一个开源的项目,发布在 GitHub 上,此项目提供了很多接口,可以用于连接远程服务器上的 docker 服务,并进行基本的操控。使用时导入 jar 包即可。相关文档及使用博客并不是很多,需要自己进行学习探索。

使用前需导入 jar 包,因为是 springboot 框架,集成了 maven ,所以直接在 pom.xml 导入依赖

        <dependency>
            <groupId>com.github.docker-javagroupId>
            <artifactId>docker-javaartifactId>
            <version>3.1.5version>
        dependency>

导入相关依赖后,编写 newContainer 类,利用 docker-java 的相关接口,实现远程服务器的 docker 服务的连接,并进行动态的创建容器、删除容器等基本操作。

package com.example.sdu_springboot_font.controller;


import com.alibaba.fastjson.JSONObject;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.model.Info;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.example.sdu_springboot_font.service.*;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/yaoyao/")//接口注解
//接收index.HTML的请求,创建一个容器,然后把跳转到容器界面
public class newContainer {
    @Autowired  //与service层进行交互
    //private LoginClservice loginClService;
    //private DockerClientUtils dockerClientUtils;
    public static int port=8080;
    public static int containerName = 0;
    @RequestMapping("user")
    public ModelAndView getLoginCl() throws InterruptedException {
        port+=1;
        containerName+=1;
        //boolean b;
        //b=loginClService.Find(name, password);//调用service层的方法
        DockerClientUtils dockerClientUtils = new DockerClientUtils();
        //连接Docker服务器
        DockerClient client = dockerClientUtils.connectDocker("tcp://82.157.124.157:2275");
        //创建容器
        CreateContainerResponse container = dockerClientUtils.createContainer(client, "ctf-test-"+containerName, "ctf-test",8080,port);
        //启动容器
        dockerClientUtils.startContainer(client, container.getId());
        //Info info = client.infoCmd().exec();

        //String infoStr = JSONObject.toJSONString(info);

        //System.out.println(infoStr);
        //return "success";
        //Thread.sleep(1000);
        return new ModelAndView("redirect:http://82.157.124.157:"+port);


    }


}

上面代码实现的测试功能为:浏览器请求 “/yaoyao/user”,服务端接收到请求后,会连接到远程服务器(82.157.124.157)的 docker 服务(2275 端口,需要在服务器端提前配置好,否则会出现拒绝连接现象)
创建容器,镜像名为 “ctf-test”,容器名为:ctf-test-编号,映射端口为服务器IP:8080

CreateContainerResponse container = dockerClientUtils.createContainer(client, "ctf-test-"+containerName, "ctf-test",8080,port);

启动容器

dockerClientUtils.startContainer(client, container.getId());

然后重定向到新创建的容器界面

return new ModelAndView("redirect:http://82.157.124.157:"+port);

3、编写 DockerClientUtils

DockerClientUtils 为 service 层文件,主要实现 docker-java 接口调用,进一步实现容器的创建删除。

package com.example.sdu_springboot_font.service;

import java.util.List;

import com.github.dockerjava.api.model.ExposedPort;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.Ports;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONObject;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.model.Info;
import com.github.dockerjava.core.DockerClientBuilder;

//import com.example.smalldemo.dao.*;
//import com.example.smalldemo.model.*;

@Service
public class DockerClientUtils {
    /**
     * 连接Docker服务器
     * @return
     */
    public DockerClient connectDocker(String dockerInstance){
        DockerClient dockerClient = DockerClientBuilder.getInstance(dockerInstance).build();
        dockerClient.infoCmd().exec();
        return dockerClient;
    }

    /**
     * 创建容器
     * @param client
     * @return

    public CreateContainerResponse createContainers(DockerClient client, String containerName, String imageName){

        CreateContainerResponse container = client.createContainerCmd(imageName)
                .withName(containerName)
                .exec();

        return container;

    }
     */
    /**
     * 创建容器
     *
     * @param client
     * @param containerName
     * @param imageName
     * @param exposedTcpPort
     * @param bindTcpPort
     * @return
     */
    public CreateContainerResponse createContainer(DockerClient client, String containerName, String imageName,
                                                   int exposedTcpPort, int bindTcpPort) {
        ExposedPort exposedPort = ExposedPort.tcp(exposedTcpPort);
        Ports portBindings = new Ports();
        portBindings.bind(exposedPort, Ports.Binding.bindPort(bindTcpPort));

        CreateContainerResponse container = client.createContainerCmd(imageName)
                .withName(containerName)
                .withHostConfig(HostConfig.newHostConfig().withPortBindings(portBindings))
                .withExposedPorts(exposedPort).exec();
        return container;
    }


    /**
     * 启动容器
     * @param client
     * @param containerId
     */
    public void startContainer(DockerClient client,String containerId){
        client.startContainerCmd(containerId).exec();
    }

    /**
     * 停止容器
     * @param client
     * @param containerId
     */
    public void stopContainer(DockerClient client,String containerId){
        client.stopContainerCmd(containerId).exec();
    }

    /**
     * 删除容器
     * @param client
     * @param containerId
     */
    public void removeContainer(DockerClient client,String containerId){
        client.removeContainerCmd(containerId).exec();
    }
/*
    public static void main(String[] args) {
        DockerClientUtils dockerClientUtils = new DockerClientUtils();
        //连接Docker服务器
        DockerClient client = dockerClientUtils.connectDocker("tcp://82.157.124.157:2275");
        //创建容器
        CreateContainerResponse container = dockerClientUtils.createContainers(client, "sny_hello1", "hello-world");
        //启动容器
        dockerClientUtils.startContainer(client, container.getId());
        Info info = client.infoCmd().exec();

        String infoStr = JSONObject.toJSONString(info);

        System.out.println(infoStr);
    }
*/
}

4、编写前端界面

前端界面仅仅作为测试使用,真正项目的前端界面由组内其他成员完成,所以这里简单的使用 HTML 编写测试界面。

  1. index.html
DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Insert title heretitle>
head>
<body>

<form name="" action="/yaoyao/user" method="post">
    <tr>
        <td>
            <input type="submit" name="tijiao" value="进入靶场容器环境"/>
        td>
    tr>

form>

body>
html>

<br>
  1. success.html
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Language" content="zh-CN">
    <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb2312">
    <meta http-equiv="refresh" content="2;url=http://82.157.124.157:8081">

    <title>创建容器成功title>
    <p>已成功创建靶场容器,即将自动跳转到靶场p>

head>
<body>

body>
html>



三、编写测试代码-模拟题目环境

这各部分主要是编写一个模拟的靶场环境,用于测试是否可以远程操控。
代码也很简单,相关的其他配置与上面一部分类似,这里便不再赘述。

package com.example.ctfzone.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class index {
    @RequestMapping("/")
    public String indexpage(){
        return "靶场环境-处于新建容器中";
    }
}



四、打包、部署、测试

1、服务器 docker 配置

环境:
centos7

开始
想要在java中还是在其他方式访问 dockerAPI 都需要设置一个端口

运行以下命令:进入docker.service

vi /lib/systemd/system/docker.service

找到 Execstart=/usr/bin/dockerd 后加上 -H tcp://0.0.0.0:2275 -H unix://var/run/docker.sock
退出并且保存

运行以下命令:

systemctl daemon-reload
 
service docker restart   //重启启动docker
 
systemctl stats docker   //可以查看相关内容,看看2275是否已经设置好

运行:netstat -nlp |grep 2275 可以查看2275是否已经被监听

如果你是阿里的云服务器这种,应该需要在安全组中加入2275或者其他的操作。

如果是在本地搭建的虚拟机,则需要把防火墙关闭或者在防火墙中开启相应端口以供外部使用


2、腾讯云防火墙端口

开启 2275 端口
山东大学软件学院项目实训-创新实训-山大软院网络攻防靶场实验平台(五)-docker容器的动态管理_第3张图片

3、dockerfile 编写

FROM java:8

COPY *.jar /app.jar

CMD ["--server.port=8080"]

EXPOSE 8080

ENTRYPOINT ["java","-jar","/app.jar" ]

4、镜像生成

  1. 生成 jar 包
    山东大学软件学院项目实训-创新实训-山大软院网络攻防靶场实验平台(五)-docker容器的动态管理_第4张图片

山东大学软件学院项目实训-创新实训-山大软院网络攻防靶场实验平台(五)-docker容器的动态管理_第5张图片

  1. 把 jar 包和 dockerfile 文件均上传到服务器
    在这里插入图片描述

  2. 生成镜像

sudo docker build -t="ctf-front-test" .

山东大学软件学院项目实训-创新实训-山大软院网络攻防靶场实验平台(五)-docker容器的动态管理_第6张图片


5、运行测试

山东大学软件学院项目实训-创新实训-山大软院网络攻防靶场实验平台(五)-docker容器的动态管理_第7张图片

山东大学软件学院项目实训-创新实训-山大软院网络攻防靶场实验平台(五)-docker容器的动态管理_第8张图片




参考文章:
https://www.cnblogs.com/lsgxeva/p/8746644.html
https://blog.csdn.net/qq_36956154/article/details/81335886

参考论文:
https://www.fx361.com/page/2021/0728/8631053.shtml

https://xueshu.baidu.com/usercenter/paper/show?paperid=1x280t10ut280mx06m080p10qj548641&site=xueshu_se

https://xueshu.baidu.com/usercenter/paper/show?paperid=1u7u0v70e02c0200j85w08h0m0022660&site=xueshu_se

https://cdmd.cnki.com.cn/article/cdmd-10013-1018097424.htm

你可能感兴趣的:(山东大学软件学院项目实训,docker,java,山东大学软件学院,容器,spring,boot)