Skip to content

Commit 70031db

Browse files
authored
Merge pull request #1206 from oracle/template-fix
Correct errors in the pod generation templating feature and improve doc.
2 parents 53cf6b6 + 0174972 commit 70031db

File tree

6 files changed

+204
-122
lines changed

6 files changed

+204
-122
lines changed

docs-source/content/userguide/managing-domains/domain-resource.md

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ The following prerequisites must be fulfilled before proceeding with the creatio
2020

2121
* Make sure the WebLogic operator is running.
2222
* Create a Kubernetes namespace for the domain resource unless the intention is to use the default namespace.
23-
* Create the Kubernetes secrets `username` and `password` of the administrative account in the same Kubernetes namespace as the domain resource.
23+
* Create the Kubernetes secrets containing the `username` and `password` of the administrative account in the same Kubernetes namespace as the domain resource.
2424

2525
#### YAML files
2626

@@ -85,7 +85,7 @@ Elements related to overriding WebLogic domain configuration:
8585
* `configOverrideSecrets`: A list of names of the secrets for optional WebLogic configuration overrides.
8686

8787
Elements related to Kubernetes pod and service generation:
88-
* `serverPod`: Configuration affecting server pods.
88+
* `serverPod`: Configuration affecting server pods for WebLogic Server instances. Most entries specify standard Kubernetes content for pods that you may want the operator to include in pods generated for WebLogic Server instances, such as labels, annotations, volumes, or scheduling constraints, including anti-affinity.
8989
* `serverService`: Customization affecting ClusterIP Kubernetes services for WebLogic Server instances.
9090

9191
Sub-sections related to the Administration Server, specific clusters or specific Managed Servers:
@@ -97,7 +97,7 @@ The elements `serverStartPolicy`, `serverStartState`, `serverPod` and `serverSer
9797

9898
### Pod generation
9999

100-
The operator creates a pod for each running WebLogic Server instance. This pod will have a container based on the Docker image specified by the `image` field. Additional pod or container content can be specified using the elements under `serverPod`. This includes Kubernetes labels and annotations, additional volumes on the pod or volume mounts on the container, [resource requirements](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/) or [security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).
100+
The operator creates a pod for each running WebLogic Server instance. This pod will have a container based on the Docker image specified by the `image` field. Additional pod or container content can be specified using the elements under `serverPod`. This includes Kubernetes sidecar and init containers, labels, annotations, volumes, volume mounts, scheduling constraints, including anti-affinity, [resource requirements](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/) or [security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).
101101

102102
Prior to creating a pod, the operator replaces variable references allowing the pod content to be templates. The format of these variable references is `$(VARIABLE_NAME)` where *VARIABLE_NAME* is one of the variable names available in the container for the WebLogic Server instance. The default set of environment variables includes:
103103
* DOMAIN_NAME: The WebLogic domain name
@@ -106,3 +106,72 @@ Prior to creating a pod, the operator replaces variable references allowing the
106106
* SERVER_NAME: The WebLogic Server name
107107
* CLUSTER_NAME: The WebLogic cluster name, if this is a cluster member
108108
* LOG_HOME: The WebLogic log location as a file system path within the container
109+
110+
This example domain YAML specifies that pods for WebLogic Server instances in the "cluster-1" cluster will have a per-managed server volume and volume mount (similar to a Kubernetes StatefulSet), an init container to initialize some files in that volume, and anti-affinity scheduling so that the server instances are scheduled as much as possible on different nodes:
111+
112+
```
113+
# Copyright 2017, 2019, Oracle Corporation and/or its affiliates. All rights reserved.
114+
# Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl.
115+
#
116+
apiVersion: "weblogic.oracle/v5"
117+
kind: Domain
118+
metadata:
119+
name: domain1
120+
namespace: domains23
121+
labels:
122+
weblogic.resourceVersion: domain-v2
123+
weblogic.domainUID: domain1
124+
spec:
125+
domainHome: /u01/oracle/user_projects/domains/domain1
126+
domainHomeInImage: true
127+
image: "phx.ocir.io/weblogick8s/my-domain-home-in-image:12.2.1.3"
128+
imagePullPolicy: "IfNotPresent"
129+
imagePullSecrets:
130+
- name: ocirsecret
131+
webLogicCredentialsSecret:
132+
name: domain1-weblogic-credentials
133+
includeServerOutInPodLog: true
134+
serverStartPolicy: "IF_NEEDED"
135+
serverPod:
136+
env:
137+
- name: JAVA_OPTIONS
138+
value: "-Dweblogic.StdoutDebugEnabled=false"
139+
- name: USER_MEM_ARGS
140+
value: "-XX:+UseContainerSupport -Djava.security.egd=file:/dev/./urandom "
141+
142+
adminServer:
143+
serverStartState: "RUNNING"
144+
145+
clusters:
146+
- clusterName: cluster-1
147+
serverStartState: "RUNNING"
148+
serverPod:
149+
affinity:
150+
podAntiAffinity:
151+
preferredDuringSchedulingIgnoredDuringExecution:
152+
- labelSelector:
153+
matchExpressions:
154+
- key: "weblogic.clusterName"
155+
operator: In
156+
values:
157+
- cluster-1
158+
topologyKey: "kubernetes.io/hostname"
159+
volumes:
160+
- name: $(SERVER_NAME)-volume
161+
emptyDir: {}
162+
volumeMounts:
163+
- mountPath: /server-volume
164+
name: $(SERVER_NAME)-volume
165+
initContainers:
166+
- name: volumeinit
167+
image: "oraclelinux:7-slim"
168+
imagePullPolicy: IfNotPresent
169+
command: ["/usr/bin/sh"]
170+
args: ["echo", "Replace with command to initialize files in /init-volume"]
171+
volumeMounts:
172+
- mountPath: /init-volume
173+
name: $(SERVER_NAME)-volume
174+
replicas: 2
175+
```
176+
177+
The operator uses an "introspection" job to discover details about the WebLogic domain configuration, such as the list of clusters and network access points. The job pod for the introspector is generated using the `serverPod` entries for the administration server. Because the administration server name is not known until the introspection step is complete, the value of the `$(SERVER_NAME)` variable for the introspection job will be "introspector".
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2019, Oracle Corporation and/or its affiliates. All rights reserved.
2+
// Licensed under the Universal Permissive License v 1.0 as shown at
3+
// http://oss.oracle.com/licenses/upl.
4+
5+
package oracle.kubernetes.operator.helpers;
6+
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.Optional;
10+
11+
import io.kubernetes.client.models.V1Container;
12+
import io.kubernetes.client.models.V1EnvVar;
13+
import io.kubernetes.client.models.V1Pod;
14+
import io.kubernetes.client.models.V1PodSpec;
15+
import oracle.kubernetes.operator.KubernetesConstants;
16+
17+
public abstract class BasePodStepContext extends StepContextBase {
18+
final <T> T updateForDeepSubstitution(V1PodSpec podSpec, T target) {
19+
return getContainer(podSpec)
20+
.map(
21+
c -> {
22+
return doDeepSubstitution(augmentSubVars(deepSubVars(c.getEnv())), target);
23+
})
24+
.orElse(target);
25+
}
26+
27+
final Map<String, String> deepSubVars(List<V1EnvVar> envVars) {
28+
return varsToSubVariables(envVars);
29+
}
30+
31+
protected Map<String, String> augmentSubVars(Map<String, String> vars) {
32+
return vars;
33+
}
34+
35+
protected Optional<V1Container> getContainer(V1Pod v1Pod) {
36+
return getContainer(v1Pod.getSpec());
37+
}
38+
39+
protected Optional<V1Container> getContainer(V1PodSpec v1PodSpec) {
40+
return v1PodSpec.getContainers().stream().filter(this::isK8sContainer).findFirst();
41+
}
42+
43+
protected boolean isK8sContainer(V1Container c) {
44+
return getMainContainerName().equals(c.getName());
45+
}
46+
47+
protected String getMainContainerName() {
48+
return KubernetesConstants.CONTAINER_NAME;
49+
}
50+
}

operator/src/main/java/oracle/kubernetes/operator/helpers/JobStepContext.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import java.util.Collections;
88
import java.util.List;
9+
import java.util.Map;
910

1011
import io.kubernetes.client.models.V1ConfigMapVolumeSource;
1112
import io.kubernetes.client.models.V1Container;
@@ -30,7 +31,8 @@
3031
import oracle.kubernetes.operator.work.Step;
3132
import oracle.kubernetes.weblogic.domain.model.Domain;
3233

33-
public abstract class JobStepContext extends StepContextBase {
34+
public abstract class JobStepContext extends BasePodStepContext {
35+
static final long DEFAULT_ACTIVE_DEADLINE_SECONDS = 120L;
3436
static final long DEFAULT_ACTIVE_DEADLINE_INCREMENT_SECONDS = 60L;
3537
private static final LoggingFacade LOGGER = LoggingFactory.getLogger("Operator", "Operator");
3638
private static final String WEBLOGIC_OPERATOR_SCRIPTS_INTROSPECT_DOMAIN_SH =
@@ -74,6 +76,20 @@ Domain getDomain() {
7476

7577
abstract String getJobName();
7678

79+
@Override
80+
protected String getMainContainerName() {
81+
return getJobName();
82+
}
83+
84+
@Override
85+
protected Map<String, String> augmentSubVars(Map<String, String> vars) {
86+
// For other introspector job pod content, we use the values that would apply administration server; however,
87+
// since we won't know the name of the administation server from the domain configuration until introspection
88+
// has run, we will use the hardcoded value "introspector" as the server name.
89+
vars.put("SERVER_NAME", "introspector");
90+
return vars;
91+
}
92+
7793
String getWebLogicCredentialsSecretName() {
7894
return getDomain().getWebLogicCredentialsSecret().getName();
7995
}
@@ -176,9 +192,11 @@ V1JobSpec createJobSpec(TuningParameters tuningParameters) {
176192
}
177193

178194
private V1PodTemplateSpec createPodTemplateSpec(TuningParameters tuningParameters) {
179-
return new V1PodTemplateSpec()
195+
V1PodTemplateSpec podTemplateSpec = new V1PodTemplateSpec()
180196
.metadata(createPodTemplateMetadata())
181197
.spec(createPodSpec(tuningParameters));
198+
199+
return updateForDeepSubstitution(podTemplateSpec.getSpec(), podTemplateSpec);
182200
}
183201

184202
private V1ObjectMeta createPodTemplateMetadata() {

operator/src/main/java/oracle/kubernetes/operator/helpers/PodStepContext.java

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
import static oracle.kubernetes.operator.VersionConstants.DEFAULT_DOMAIN_VERSION;
6262

6363
@SuppressWarnings("deprecation")
64-
public abstract class PodStepContext extends StepContextBase {
64+
public abstract class PodStepContext extends BasePodStepContext {
6565

6666
private static final LoggingFacade LOGGER = LoggingFactory.getLogger("Operator", "Operator");
6767

@@ -375,14 +375,6 @@ V1Pod createPodModel() {
375375
return withNonHashedElements(AnnotationHelper.withSha256Hash(createPodRecipe()));
376376
}
377377

378-
protected Optional<V1Container> getContainer(V1Pod v1Pod) {
379-
return v1Pod.getSpec().getContainers().stream().filter(this::isK8sContainer).findFirst();
380-
}
381-
382-
protected boolean isK8sContainer(V1Container c) {
383-
return KubernetesConstants.CONTAINER_NAME.equals(c.getName());
384-
}
385-
386378
V1Pod withNonHashedElements(V1Pod pod) {
387379
V1ObjectMeta metadata = pod.getMetadata();
388380
// Adds labels and annotations to a pod, skipping any whose names begin with "weblogic."
@@ -395,21 +387,11 @@ V1Pod withNonHashedElements(V1Pod pod) {
395387

396388
updateForStartupMode(pod);
397389
updateForShutdown(pod);
398-
updateForDeepSubstitution(pod);
399-
400-
return pod;
401-
}
402-
403-
final void updateForDeepSubstitution(V1Pod pod) {
404-
getContainer(pod)
405-
.ifPresent(
406-
c -> {
407-
doDeepSubstitution(deepSubVars(c.getEnv()), pod);
408-
});
390+
return updateForDeepSubstitution(pod.getSpec(), pod);
409391
}
410392

411-
final Map<String, String> deepSubVars(List<V1EnvVar> envVars) {
412-
Map<String, String> vars = varsToSubVariables(envVars);
393+
@Override
394+
protected Map<String, String> augmentSubVars(Map<String, String> vars) {
413395
String clusterName = getClusterName();
414396
if (clusterName != null) {
415397
vars.put("CLUSTER_NAME", clusterName);

0 commit comments

Comments
 (0)