WSL2+Docker+IDEA一站式开发调试

前言

​ 我们知道,Docker是一个容器引擎;对于开发者来说,使用Dokcer容器部署各种开发需要的中间件(比如myql、redis)会非常简单方便;效率更高。Docker天生是完美支持Linux的,但大多数开发者都是在windows环境下进行开发,虽然Docker也兼容Windows;但并不是那么完美。好在,微软推出了WSL2(全称:Windows Subsystem for Linux),即Windows的Linux子系统;子系统运行真正的 Linux 内核,可以完美支持Docker。而新版IDEA支持Docker远程连接进行开发调试。因此WSL2+Docker+IDEA进行开发可以说是最佳搭配。本文就是介绍如何使用这三者搭建开发环境的。

环境配置

WSL2:安装的是CentOS7

Docker:版本20.10.14;已开启远程访问;开启方式可参考文章:docker开启远程访问

IDEA:版本为2022.1.1

创建springboot应用

为了测试环境效果,我们先简单创建一个最基础的springboot应用,打开IDEA,选择New Project,如图:

图示修改说明:

① 原URL为https://start.spring.io ;可能会因为网络问题无法访问而导致创建失败,因此改为:https://start.aliyun.com

② 自定义项目名称

③ 自定义项目存放目录

④ 按需选择JDK和JAVA版本

上面信息填写完成后,点击Next:

在这一步,只勾选 Lombok 和 Spring Web即可。然后点击Create,即可创建一个最简单的springboot应用。创建完成后的pom.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>dev-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>dev-demo</name>
<description>dev-demo</description> <properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<configuration>
<mainClass>com.example.devdemo.DevDemoApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build> </project>

我们再新建一个controller包,在包中新建一个DemoController类,在类中添加一个web响应接口:

package com.example.devdemo.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date; @Slf4j
@RestController
public class DemoController {
@RequestMapping("/test")
public String test(){
log.info("测试接口:Hello world, docker!");
return "Hello world, docker!" + new SimpleDateFormat(" [yyyy-MM-dd HH:mm:ss]").format(new Date());
}
}

以上,我们的demo应用创建完毕,点击运行,然后访问:http://localhost:8080/test 即可看到如下效果:

配置IDEA远程连接Docker进行打包部署并进行debug调试

IDEA远程连接Docker的方式有两种:分别是IDEA自带插件方式和maven插件方式

方式一:IDEA插件远程连接Docker打包部署

  1. 在idea中配置docker远程连接

    如图,在设置中填写好Name和Engine API URL后,如果显示Connection successful即为成功连接到远程docker。URL中的windows.wsl为我的WSL2地址,我做了host映射。

    踩坑记录:如果是使用WSL2的,windows.wsl可以改为localhost;但经过测试,在win10的wsl2中,使用localhost能成功连接docker;但在win11中却不行。如果localhost无法连接到wsl2的Docker,则需要使用脚本对wsl2进行固定IP,然后像我一样做host映射即可;可参考我另一篇文章:WSL2-CenOS7固定IP,这里不再表述。

  2. 创建Dockerfile并进行运行环境配置

    • 在项目根目录下创建Dockerfile文件,并写入如下内容:

      # Docker image for springboot application
      # VERSION 0.0.1
      # Author: Lunfy ### 基础镜像; 直接基于java8运行
      FROM anapsix/alpine-java #作者
      MAINTAINER Lunfy <lunfy@qq.com> #系统编码
      ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 #设置时区
      ENV TZ=Asia/Shanghai
      RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone #声明一个挂载点,容器内此路径会对应宿主机的某个文件夹
      VOLUME /tmp #应用构建成功后的jar文件被复制到镜像内,名字也改成了app.jar
      ADD target/dev-demo-0.0.1-SNAPSHOT.jar app.jar #暴露8080端口;5005为远程调试端口,根据需要选择是否暴露
      EXPOSE 8080 5005 #启动容器时的进程
      #ENTRYPOINT ["java","-jar","/app.jar"] #远程调试
      ENTRYPOINT ["java","-jar","-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005","app.jar"]
    • 如图所示创建一个配置文件

    • 配置详情如下图:

      上图中Run Maven Goal添加配置运行前的mavne打包命令为:clean package -U -DskipTests; 注意,不带mvn指令;表示每次在构建镜像之前,都会将当前工程清理掉并且重新编译构建

    • 设置完成后,点击下图红框中的绿色三角按钮,运行此配置

  3. 运行结果

    • 运行后,控制台效果如下:

    • 打开浏览器,输入http://localhost:18080/test;效果如下:

    • 打开WSL2,使用docker命令查看镜像和容器

      查看镜像:docker images 查看容器:docker ps -a

  4. 远程debug配置

    上面我们已完成了应用的容器构建和部署运行;但作为开发,也许我们还会经常用到debug功能;但应用部署在远程docker容器中,我们该怎么进行debug呢?这时,我们就需要用到IDEA的远程debug功能了。

    • 和前面添加配置一样,点击Edit Configurations...创建配置文件

    • 配置详情如图:

      需要特别说明的是,之前dockerfile配置文件的ENTRYPOINT开启远程调试的配置,就是从Command line arguments for remote JVM这里复制的命令。另外,因为我是WSL2,所以远程主机填的是localhost;端口可根据需要自定义。

    • 开始远程debug;

      我们给应用打上断点,然后点击debug图标开始运行。之后在控制台出现“Connected to the target VM”字样,即为成功连接到远程的虚拟机上。这时,再次在浏览器访问 http://localhost:18080/test 即可看到程序进入断点:

至此,IDEA插件方式远程连接打包部署并远程调试完毕。

方式二:MAVEN插件远程连接Docker打包部署(推荐)

  1. 创建Dockerfile(在此直接使用方式一的Dockerfile文件,如没有,需创建)。

  2. 在pom.xml中配置插件信息;参考:docker-maven-plugin插件官方文档 在标签中添加如下配置:

                <!-- docker-maven-plugin 插件 -->
    <plugin>
    <groupId>io.fabric8</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.39.1</version>
    <!-- 全局配置 -->
    <configuration>
    <!-- 这一部分是为了实现对远程docker容器的控制 -->
    <!-- docker主机地址,用于完成docker各项功能;tcp或者http均可! -->
    <dockerHost>tcp://localhost:2375</dockerHost>
    <!-- <dockerHost>http://localhost:2375</dockerHost> --> <!-- 这一部分是为了实现docker镜像的构建和推送,如果不需要可不配置; 比如我就只是在本地WSL环境开发,所以不配置 -->
    <!-- registry地址,用于推送,拉取镜像
    <registry>registry.example.com</registry>
    <authConfig>
    <push>
    <username>这里填registry的用户名</username>
    <password>这里填registry的密码</password>
    </push>
    </authConfig>
    --> <!-- 镜像相关配置,支持多镜像-->
    <images>
    <!-- 单个镜像配置 -->
    <image>
    <!-- 镜像名(含标签); 标准镜像名格式为:命名空间/仓库名称:镜像标签;如标签不填,则默认为latest -->
    <!--例: <name>lunfy/devdemo:test</name> -->
    <name>lunfy/devdemo</name>
    <!-- 镜像别名;可用于作为容器名(服务名称) -->
    <alias>demo-service</alias>
    <build>
    <!-- 可指定Dockerfile目录或者指定Dockerfile文件;配置二选一即可 --> <!-- 指定dockerfile所在目录 -->
    <!-- <contextDir>${project.basedir}</contextDir> --> <!-- 指定dockerfile文件的位置 -->
    <dockerFile>${project.basedir}/Dockerfile</dockerFile>
    </build> <!-- 配置docker-compose文件
    <external>
    <type>compose</type>
    <basedir>${project.basedir}/docker</basedir>
    <composeFile>docker-compose.yml</composeFile>
    </external>
    --> <run>
    <!-- 容器运行端口映射,对应docker的 -p 命令 -->
    <ports>
    <port>28080:8080</port>
    <port>5005:5005</port>
    </ports>
    <!-- 容器命名策略:alias:使用镜像别名作为容器名;none:随机命名 -->
    <namingStrategy>alias</namingStrategy>
    </run> </image>
    </images>
    </configuration> <executions>
    <execution>
    <id>docker-exec</id>
    <!-- 绑定mvn install阶段,当执行mvn install时 就会执行docker stop、docker build、docker start -->
    <phase>install</phase>
    <goals>
    <!-- 要先停止并删除容器,否则下一步删除镜像会报错 -->
    <goal>stop</goal>
    <!-- 删除镜像;此步可省略,build构建的时候会自动删除 -->
    <!-- <goal>remove</goal> -->
    <!-- 构建镜像 -->
    <goal>build</goal>
    <!-- 启动容器 -->
    <goal>start</goal> <!-- 运行容器:
    run和start的区别:
    run:在前台运行docker容器,容器直接与idea联动;日志会直接输出到idea控制台,可以在idea直接控制容器状态。在idea点击停止按钮,容器停止运行。
    start: 在后台运行docker容器;容器与idea解耦;日志不会输出到idea控制台;和正常在命令行启动docker一样
    -->
    <!-- <goal>run</goal> -->
    </goals>
    </execution>
    </executions>
    </plugin>

    配置中已有注释,这里不再做说明

  3. 运行结果

    • 配置完pom.xml后,在应用打上断点,然后双击install即可开始运行;如果前面按照方式一构建运行过docker; 记得要先在WSL2中把容器删除(虽然是同一dockerfile构建的镜像,但maven删除无法自动删除别的插件运行产生的镜像),否则会出现如下报错:

    • 执行命令把容器删除:

    • 再次双击install运行

    • 访问 http://localhost:18080/test

    • 点击停止按钮,容器停止运行;和方式一不一样,此时去WSL2中已查看到不窗口进行。也就是说,在这种方式下,WSL2中的容器是随着IDEA的停止而销毁的。

    两种方式效果差异:

    • 方式一会随着项目不断重复构建,而产生很多个标签的镜像;但方式二却不会。方式二不管构建多少次,都只会产生一个镜像。

      idea dockder反复打包后,会有很多标签的镜像

      解决办法:使用以下指令进行快速删除

      docker rmi -f $(docker images | grep "none" | awk '{print $3}')

      或者

      docker rmi -f $(docker images -f "dangling=true" -q)

      或者

      docker image prune -f

      深度清理命令:docker image prune -a -f

      这个命令将清理整个系统,并且只会保留真正在使用的镜像,容器,数据卷以及网络,因此需要格外谨慎。

      比如,我们不能在生产环境中运行prune -a命令,因为一些备用镜像(用于备份,回滚等)有时候需要用到,如果这些镜像被删除了,则运行容器时需要重新下载。

    • Maven插件方式功能强大,从docker的构建、运行、推送等等全流程支持;而且经过配置,即使多次重复构建镜像,也不会像idea插件一样产生很多个标签的镜像;非常适合开发调试使用。这也是推荐的最大理由。

    • Maven插件方式部署步骤比较少,但需要对docker-maven-plugin的配置比较了解;而IDEA插件配置方式虽然步骤多一些,但都是图形化配置。比较方便。因此可根据需要进行选择。

    最后附上Demo代码:https://gitee.com/lunfangyu/dev-demo

WSL2+Docker+IDEA一站式开发调试的更多相关文章

  1. envoy开发调试环境搭建

    image 前段时间研究envoy的filter开发,在windows机器环境上面折腾了会,这里记录一下,希望能够帮助到大家少走一些坑 主要是使用vscode devContainer的方式来搭建开发 ...

  2. Fabric Dev开发调试模式的搭建过程

    在利用Fabric开发Chaincode的时候,调试Chaincode显得尤为不方便,因为Chaincode正常应该运行在Docker容器中,每次修改Chaincode后想要使其更改生效必须得对Cha ...

  3. Swoft 新手向教程 - 通过 Docker 搭建一个开发环境

    本系列文章将从使用层面介绍 Swoft 框架的使用及业务开发,面向初中级的 PHPer Swoft首个基于 Swoole 原生协程的新时代 PHP 高性能协程全栈组件化框架,内置协程网络服务器及常用的 ...

  4. 玩转VSCode-完整构建VSCode开发调试环境

    随着VSCode的不断完善和强大,是时候将部分开发迁移到VS Code中了. 目前使用VS2019开发.NET Core应用,一直有一个想法,在VS Code中复刻VS的开发环境,同时迁移到VS Co ...

  5. 使用vscode Container开发调试envoy

    由于我最近在研究 envoy 这个项目,这是个cpp的项目,对于我这种cpp新人来说还是比较有压力的,感觉处处都是坑,开个引导文章记录一下. 如果要研究 envoy 项目源码,那肯定是需要代码跳转的, ...

  6. 【视频】k8s套娃开发调试dapr应用 - 在6月11日【开源云原生开发者日】上的演示

    这篇博客是在2022年6月11日的[开源云原生]大会上的演讲中的演示部分.k8s集群套娃(嵌套)是指在一个k8s的pod中运行另外一个k8s集群,这想法看上去很疯狂,实际上非常实用. k8s集群套娃( ...

  7. 使用VS Code从零开始开发调试.NET Core 1.0

    使用VS Code 从零开始开发调试.NET Core 1.0. .NET Core 是一个开源的.跨平台的 .NET 实现. VS Code 全称是 Visual Studio Code,Visua ...

  8. Docker 创建php 开发环境遇到的权限问题解决方案

    最近我将公司的开发,和测试环境都运行到docker 上面,因为开发,测试基本都是装代码拉到本址,然后,再装目录,挂载到镜像目录中如:我用的是docker-compose # development.y ...

  9. 使用VS Code开发调试.NET Core 多项目

    使用Visual Studio Code(VS Code)开发调试.NET Core和ASP.NET Core 多项目multiple project. 之前讲解过如果使用Visual Studio ...

随机推荐

  1. ACM - 最短路 - AcWing 849 Dijkstra求最短路 I

    AcWing 849 Dijkstra求最短路 I 题解 以此题为例介绍一下图论中的最短路算法.先让我们考虑以下问题: 给定一个 \(n\) 个点 \(m\) 条边的有向图(无向图),图中可能存在重边 ...

  2. Linux 0.11源码阅读笔记-文件管理

    Linux 0.11源码阅读笔记-文件管理 文件系统 生磁盘 未安装文件系统的磁盘称之为生磁盘,生磁盘也可以作为文件读写,linux中一切皆文件. 磁盘分区 生磁盘可以被分区,分区中可以安装文件系统, ...

  3. Redis分布式实现原理

    一.使用 1.pom.xml导入依赖 <dependency> <groupId>org.springframework.boot</groupId> <ar ...

  4. MyBatis 及 MyBatis Plus 纯注解方式配置(Spring Boot + Postgresql)

    说明 当前的版本为 MyBatis 3.5.9 MyBatis Plus 3.5.1 Spring Boot 2.6.4 Postgresql 42.3.3 与 Spring Boot 结合使用 My ...

  5. Ubuntu20.04中创建Pycharm桌面快捷方式

    [Desktop Entry] Type=Application Name=Pycharm GenericName=Pycharm3 Comment=Pycharm3:The Python IDE E ...

  6. 不用关闭重启cad及不用更改快捷方式或者版本号c#调试cad插件

    c#开发的cad插件需要重启cad才能进行调试,然而高版本的cad启动比较慢特别是一些古董电脑,而且cad有重启次数限制.针对不用重启cad调试已经有成熟的方案了,但是需要调试一次修改一次快捷方式或者 ...

  7. 【LeetCode】358.K 距离间隔重排字符串

    358.K 距离间隔重排字符串 知识点:哈希表:贪心:堆:队列 题目描述 给你一个非空的字符串 s 和一个整数 k,你要将这个字符串中的字母进行重新排列,使得重排后的字符串中相同字母的位置间隔距离至少 ...

  8. 异步任务-springboot

    异步任务-springboot 异步:异步与同步相对,当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作.也就是说无论异步方法执行代码需要多长时间,跟主线程没有任何影响,主线程 ...

  9. 帝国CMS如何互相转移分表之间的数据

    最近发现帝国CMS文章数据添加太多到某一张分表中了,如图 这是极其不合理的,需要优化下,所以这篇文章要告诉大家的也就是如何互相转移分表之间的数据. 我现在要将:phome_ecms_news_data ...

  10. 硬核 | Redis 布隆(Bloom Filter)过滤器原理与实战

    在Redis 缓存击穿(失效).缓存穿透.缓存雪崩怎么解决?中我们说到可以使用布隆过滤器避免「缓存穿透」. 码哥,布隆过滤器还能在哪些场景使用呀? 比如我们使用「码哥跳动」开发的「明日头条」APP 看 ...