在容器中开发应用

### 使用容器作为调试环境

我的`IntelliJ IDEA`安装在Windows主机上，在`VirtualBox`上安装了`ubuntu server`。目标是在Windows主机上编译、单元测试，在容器内进行集成测试。

#### 应用

一个简单的`spring boot`项目
```java
// io.github.jyjw.podmanrunner.Application
@SpringBootApplication  
@RestController  
public class Application {  
  
    @GetMapping("/hello")  
    public ResponseEntity<Map<String, String>> hello() {  
        return ResponseEntity.ok(Map.of("message", "hello"));  
    }  
  
    public static void main(String[] args) {  
        SpringApplication.run(Application.class);  
    }  
}
```

```groovy
// build.gradle
import java.nio.file.Paths  
  
plugins {  
    id 'org.springframework.boot' version '2.7.1'  
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'  
    id 'java'  
}  
  
group = 'io.github.jyjw'  
version = '0.0.1-SNAPSHOT'  
sourceCompatibility = '11'  
  
repositories {  
    mavenCentral()  
}  
  
dependencies {  
    implementation 'org.springframework.boot:spring-boot-starter-web'  
    testImplementation 'org.springframework.boot:spring-boot-starter-test'  
}  
  
tasks.named('test') {  
    useJUnitPlatform()  
}  
  
  
// copy dependencies before compile classes  
  
task copyDependencyJars {  
    def dependencyJarDir = Paths.get(projectDir.getAbsolutePath(), 'env/libs').toString()  
    mkdir dependencyJarDir  
    def artifacts = configurations.runtimeClasspath.resolvedConfiguration.resolvedArtifacts  
    artifacts.forEach {artifact-> copy {  
        from artifact.file  
        into dependencyJarDir  
  
        def destFile = Paths.get(dependencyJarDir.toString(), artifact.file.name).toFile()  
        exclude {destFile.exists()}  
    }}}  
  
tasks.named('classes') {  
    dependsOn copyDependencyJars  
}

```

```properties
# application.properties
server.port=7778
```

没有多少特别的，所有运行时需要的jar包被复制到`env/libs`目录

#### pod.env.yaml

准备一个`pdoman`配置文件
```yaml
---  
apiVersion: v1  
kind: Pod  
metadata:  
  name: dev-env  
  labels:  
    app: dev-env  
    environment: dev  
spec:  
  containers:  
    - name: java-env  
      image: openjdk:11-jre-slim-bullseye  
      workingDir: /artifacts  
      command:  
        - "java"  
        - "-cp"  
        - ".:libs/*"
        - "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:7779"
        - "io.github.jyjw.podmanrunner.Application"  
      volumeMounts:  
        - mountPath: /artifacts  
          name: artifacts  
      ports:  
        - containerPort: 7778  
          hostPort: 7778  
        - containerPort: 7779  
          hostPort: 7779  
  volumes:  
    - name: artifacts  
      hostPath:  
        path: artifacts  
        type: Directory
```

这里配置了两个端口，端口7778归应用使用，7779用于调试。挂载了一个目录，在此目录下将会是应用相关文件。
我们使用scp将此文件复制到虚拟机，在虚拟机中使用命令以下创建`pod`
```shell
sudo podman play kube pod.dev.yaml
```
常用命令
```shell
# inspect
sudo podman pod inspect dev-env
# stop
sudo podman pod stop dev-env
# rm
sudo podman pod rm dev-env
# logs
sudo podman logs -f dev-env-java-env
```

#### rsync
我们需要把编译好的文件同步到容器中，这里使用`cwrsync`。下面的脚本将会完成同步工作
```batch
@echo off  
  
REM cwRsync, download from https://chocolatey.org/packages/rsync/5.5.0.20180618  
REM %CWRSYNCHOME% where you install cwrsync
set "rsync_dir=%CWRSYNCHOME%\bin"  
REM ssh connect parameters  
set "ssh_args=%CWRSYNC_SSH_ARGS%"  
  
pushd "%~dp0"  
  
"%rsync_dir%\rsync.exe" -e "%rsync_dir%\ssh.exe %ssh_args%" --delete -r^  
  --include=libs^  
  --include=../build/classes/java/main/^  
  --include=../build/resources/main/^  
  :~/artifacts  
  
popd
```

#### 测试
在虚拟机中使用如下命令即可测试服务是否运行成功
```shell
curl http://localhost:7778/hello
```

#### 远程调试
`IntelliJ IDEA`使用`Remote Debug`选项即可实现远程调试

### 使用`IntelliJ IDEA`的Docker插件

IDEA的Docker插件可以利用podman服务器实现镜像生成和容器运行。在虚拟机中使用如下命令，启动podman api service。
```shell
sudo podman system service --time 0 tcp:0:0:0:0:8080
```

接下来还需在IDEA中配置Docker服务器。（略）之后点击Docker文件，即可生成并部署到podman服务器中。
Dockerfile
```Dockerfile
  
FROM openjdk:11-jre-slim-bullseye  
  
RUN mkdir -p "/artifacts/libs"  
WORKDIR "/artifacts"  
  
COPY env/libs /artifacts/libs  
COPY build/resources/main/* /artifacts  
COPY build/classes/java/main /artifacts  
  
# 需要在启动设置内公开端口  
EXPOSE 7778  
EXPOSE 7779  
  
CMD ["java", "-cp", ".:libs/*", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:7779", "io.github.jyjw.podmanrunner.Application"]
```