88import com .github .dockerjava .api .command .InspectContainerResponse ;
99import com .github .dockerjava .api .model .DockerObjectAccessor ;
1010import lombok .SneakyThrows ;
11+ import org .apache .commons .io .IOUtils ;
1112import org .testcontainers .containers .BindMode ;
1213import org .testcontainers .containers .GenericContainer ;
1314import org .testcontainers .containers .wait .strategy .LogMessageWaitStrategy ;
1415import org .testcontainers .utility .DockerImageName ;
1516
17+ import java .nio .charset .StandardCharsets ;
1618import java .util .HashMap ;
1719import java .util .Map ;
1820
1921public class K3sContainer extends GenericContainer <K3sContainer > {
2022
23+ public static int KUBE_SECURE_PORT = 6443 ;
24+
25+ public static int RANCHER_WEBHOOK_PORT = 8443 ;
26+
2127 private String kubeConfigYaml ;
2228
2329 public K3sContainer (DockerImageName dockerImageName ) {
2430 super (dockerImageName );
2531 dockerImageName .assertCompatibleWith (DockerImageName .parse ("rancher/k3s" ));
2632
27- addExposedPorts (6443 , 8443 );
33+ addExposedPorts (KUBE_SECURE_PORT , RANCHER_WEBHOOK_PORT );
2834 setPrivilegedMode (true );
2935 withCreateContainerCmdModifier (it -> {
3036 it .getHostConfig ().withCgroupnsMode ("host" );
@@ -44,30 +50,57 @@ public K3sContainer(DockerImageName dockerImageName) {
4450 setWaitStrategy (new LogMessageWaitStrategy ().withRegEx (".*Node controller sync successful.*" ));
4551 }
4652
47- @ SneakyThrows
4853 @ Override
4954 protected void containerIsStarted (InspectContainerResponse containerInfo ) {
55+ String rawKubeConfig = copyFileFromContainer ("/etc/rancher/k3s/k3s.yaml" ,
56+ is -> IOUtils .toString (is , StandardCharsets .UTF_8 )
57+ );
58+ String serverUrl = "https://" + this .getHost () + ":" + this .getMappedPort (KUBE_SECURE_PORT );
59+ kubeConfigYaml = kubeConfigWithServerUrl (rawKubeConfig , serverUrl );
60+ }
61+
62+ /**
63+ * Return the kubernetes client configuration to access k3s from the host machine.
64+ *
65+ * @return the kubeConfig yaml.
66+ */
67+ public String getKubeConfigYaml () {
68+ return kubeConfigYaml ;
69+ }
70+
71+ /**
72+ * Generate a kubernetes client configuration for use on a docker internal network. The kubeConfig can be used by
73+ * another docker container running in the same network as the k3s container. For access from the host, use
74+ * the {@link #getKubeConfigYaml()} method instead.
75+ *
76+ * @param networkAlias a valid network alias of the k3s container.
77+ * @return the kubeConfig yaml.
78+ */
79+ public String generateInternalKubeConfigYaml (String networkAlias ) {
80+ if (this .getNetworkAliases ().contains (networkAlias )) {
81+ String serverUrl = "https://" + networkAlias + ":" + KUBE_SECURE_PORT ;
82+ return kubeConfigWithServerUrl (kubeConfigYaml , serverUrl );
83+ } else {
84+ throw new IllegalArgumentException (networkAlias + " is not a network alias for k3s container" );
85+ }
86+ }
87+
88+ @ SneakyThrows
89+ private String kubeConfigWithServerUrl (String kubeConfigYaml , String serverUrl ) {
5090 ObjectMapper objectMapper = new ObjectMapper (new YAMLFactory ());
5191
52- ObjectNode rawKubeConfig = copyFileFromContainer (
53- "/etc/rancher/k3s/k3s.yaml" ,
54- is -> objectMapper .readValue (is , ObjectNode .class )
55- );
92+ ObjectNode kubeConfigObjectNode = objectMapper .readValue (kubeConfigYaml , ObjectNode .class );
5693
57- JsonNode clusterNode = rawKubeConfig .at ("/clusters/0/cluster" );
94+ JsonNode clusterNode = kubeConfigObjectNode .at ("/clusters/0/cluster" );
5895 if (!clusterNode .isObject ()) {
5996 throw new IllegalStateException ("'/clusters/0/cluster' expected to be an object" );
6097 }
6198 ObjectNode clusterConfig = (ObjectNode ) clusterNode ;
99+ clusterConfig .replace ("server" , new TextNode (serverUrl ));
62100
63- clusterConfig . replace ( "server " , new TextNode ("https://" + this . getHost () + ":" + this . getMappedPort ( 6443 ) ));
101+ kubeConfigObjectNode . set ( "current-context " , new TextNode ("default" ));
64102
65- rawKubeConfig .set ("current-context" , new TextNode ("default" ));
66-
67- kubeConfigYaml = objectMapper .writerWithDefaultPrettyPrinter ().writeValueAsString (rawKubeConfig );
68- }
69-
70- public String getKubeConfigYaml () {
71- return kubeConfigYaml ;
103+ return objectMapper .writerWithDefaultPrettyPrinter ()
104+ .writeValueAsString (kubeConfigObjectNode );
72105 }
73106}
0 commit comments