Skip to content

Commit 9292735

Browse files
authored
INITIAL version of CI/CD doc (#1035)
* add first version of ci/cd documenation * review and edit, jenkins-ignore * fix typo, jenkins-ignore * updates from review comments * updates from review
1 parent 4211cb1 commit 9292735

15 files changed

+432
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
title: "CI/CD considerations"
3+
date: 2019-04-11T13:01:55-04:00
4+
weight: 5
5+
description: "Learn about managing domain images with CI/CD."
6+
draft: false
7+
---
8+
9+
### Overview
10+
11+
In this section, we will discuss the recommended techniques for managing the evolution
12+
and mutation of Docker images to run WebLogic in Kubernetes. There are several
13+
approaches and techniques available, and the choice of which to use depends very
14+
much on your particular requirements. We will start with a review of the "problem
15+
space," and then talk about the considerations that would lead us to choose various
16+
approaches. We will provide details about several approaches to implementing
17+
CI/CD and links to examples.
18+
19+
### Review of the problem space
20+
21+
Kubernetes makes a fundamental assumption that Docker images are immutable,
22+
that they contain no state, and that updating them is as simple as throwing
23+
away a pod/container and replacing it with a new one that uses a newer version
24+
of the Docker image. These assumptions work very well for microservices
25+
applications, but for more traditional workloads, we need to do some extra
26+
thinking and some extra work to get the behavior we want.
27+
28+
CI/CD is an area where the standard assumptions aren't always suitable. In the
29+
microservices architecture, you typically minimize dependencies and build
30+
images from scratch with all of the dependencies in them. You also typically
31+
keep all of the configuration outside of the image, for example, in Kubernetes config
32+
maps or secrets, and all of the state outside of the image too. This makes
33+
it very easy to update running pods with a new image.
34+
35+
Let's consider how a WebLogic image is different. There will, of course, be a
36+
base layer with the operating system; let's assume it is
37+
[Oracle Linux "slim"](https://hub.docker.com/_/oraclelinux/). Then you need
38+
a JDK and this is very commonly in another layer. Many people will use
39+
the officially supported JDK images from the Docker Store, like the
40+
[Server JRE image](https://hub.docker.com/_/oracle-serverjre-8), for example. On
41+
top of this, you need the WebLogic Server binaries (the "Oracle Home"). On top
42+
of that, you may wish to have some patches or updates installed. And then
43+
you need your domain, that is the configuration.
44+
45+
There is also other information associated with a domain that needs to live
46+
somewhere, for example leasing tables, message and transaction stores, and so
47+
on. We recommend that these be kept in a database to take advantage of built-in
48+
database server HA, and the fact that disaster recovery of sites across all
49+
but the shortest distances almost always requires using a single database
50+
server to consolidate and replicated data (DataGuard).
51+
52+
There are two common approaches on how to structure these components. The first,
53+
which we call "domain on persistent volume," places the JDK and WebLogic binaries
54+
in the Docker image, but the domain is kept on a separate persistent storage
55+
outside of the image. The second approach puts the JDK, WebLogic binaries
56+
and the domain all in the Docker image. Both of these approaches are perfectly
57+
valid (and fully supported) and they have various advantages and disadvantages.
58+
59+
We have listed the [relative advantages of these two approaches here]({{< relref "/userguide/managing-domains/choosing-a-model/_index.md" >}}).
60+
61+
One of the key differences between these approaches is how many Docker images
62+
you have, and therefore, how you build and maintain them - your image CI/CD
63+
process. Let's take a short detour and talk about Docker image layering.
64+
65+
{{% children style="h4" description="true" %}}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
---
2+
title: "Choose an approach"
3+
date: 2019-04-11T13:36:57-04:00
4+
draft: false
5+
weight: 3
6+
description: "How to choose an approach."
7+
---
8+
9+
Let's review what we have discussed and talk about when we might want to use
10+
various approaches. We can start by asking ourselves questions like these:
11+
12+
13+
- *Can you make the desired change with a configuration override?*
14+
The WebLogic Kubernetes Operator allows you to inject a number of [configuration
15+
overrides]({{< relref "/userguide/managing-domains/configoverrides/_index.md" >}})
16+
into your pods before starting any servers in the domain. This allows you to use
17+
the same image for multiple
18+
different configurations. A good example would be changing the settings for a data
19+
source, for example. You may wish to have a larger connection pool in your production
20+
environment than you do in your development/test environments. You probably also
21+
want to have different credentials. You may want to change the service name, and
22+
so on. All of these kinds of updates can be made with configuration overrides.
23+
These are placed in a Kubernetes config map, that is, they are outside of the image, so
24+
they do not require rebuilding the Docker image. If all of your changes fit into
25+
this category, it is probably much better to just use configuration overrides
26+
instead of building a new image.
27+
- *Are you only changing the WebLogic configuration, for example, deploying or updating an
28+
application, changing a resource configuration in a way that is not supported by
29+
configuration overrides, and such?*
30+
If your changes fit into this category, and you have used the "domain-in-image"
31+
approach and the Docker layering model, then you only need to update the top layer
32+
of your image. This is relatively easy compared to making changes in lower layers.
33+
You could create a new layer with the changes, or you could rebuild/replace the
34+
existing top layer with a new one. Which approach you choose depends mainly on
35+
whether you need to maintain the same domain encryption keys or not.
36+
- *Do you need to be able to do a rolling restart?*
37+
If you need to do a rolling restart, for example to maintain the availability of
38+
your applications, then you need to make sure the new domain layer has the same
39+
domain encryption keys. You cannot perform a rolling restart of a domain if the
40+
new members have a different encryption key.
41+
- *Do you need to mutate something in a lower layer, for example, patch WebLogic, the JDK, or Linux?*
42+
If you need to make an update in a lower layer, then you will need to rebuild that
43+
layer and all of the layers above it. This means that you will need to rebuild the
44+
domain layer. You will need to determine if you need to keep the same domain encryption keys.
45+
46+
The diagram below summarizes these concerns in a decision tree for the “domain in image” case:
47+
48+
![Decision model for the "domain in image" approach](/weblogic-kubernetes-operator/images/flowchart.png)
49+
50+
If you are using the "domain on persistent storage" approach, many of these concerns become
51+
moot because you have an effective separation between your domain and the Docker image.
52+
There is still the possibility that an update in the Docker image could affect your domain;
53+
for example, if you updated the JDK, you may need to update some of your domain scripts
54+
to reflect the new JDK path.
55+
56+
However, in this scenario, your environment is much closer to what you are probably used
57+
to in a traditional (non-Kubernetes) environment, and you will probably find that all of
58+
the practices you used from that pre-Kubernetes environment are directly applicable here
59+
too, with just some small modifications. For example, applying a WebLogic patch would
60+
now involve building a new Docker image.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
title: "How to copy domains"
3+
date: 2019-04-11T13:48:15-04:00
4+
draft: false
5+
weight: 5
6+
description: "How to copy domains."
7+
---
8+
9+
The recommended approach to save a copy of a domain is to simply ZIP (or tar)
10+
the domain directory. However, there is a very important caveat with this
11+
recommendation - when you unzip the domain, it must go back into exactly
12+
the same location (Domain Home) in the (new) file system. Using this
13+
approach will maintain the same domain encryption key.
14+
15+
The best practice/recommended approach is to create a "primordial domain"
16+
which does not contain any applications or resources,
17+
and to create a ZIP file of this domain before starting any servers.
18+
19+
> The domain ZIP must be created before starting servers.
20+
21+
When servers are started the first time, they will encrypt various other data.
22+
Make sure you create the ZIP file before starting servers for the first time.
23+
The primordial domain ZIP file should be stored in a safe place where the CI/CD
24+
can get it when needed, for example in a secured Artifactory repository (or
25+
something similar).
26+
27+
{{% notice warning %}}
28+
Remember, anyone who gets access to this ZIP file can get access
29+
to the domain encryption key, so it needs to be protected appropriately.
30+
{{% /notice %}}
31+
32+
Every time you run your CI/CD pipeline to create a new mutation of the domain,
33+
it should retrieve and unzip the primordial domain first, and then apply changes
34+
to that domain using tools like WDT or WLST (see [here]({{< relref "/userguide/cicd/tools.md" >}})).
35+
36+
37+
> Always use external state.
38+
39+
You should always keep state outside the Docker image. This means that you should
40+
use JDBC stores for leasing tables, JMS and Transaction stores,
41+
EJB timers, JMS queues, and so on. This ensures that data will not be lost when
42+
a container is destroyed.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
title: "Docker image layering"
3+
date: 2019-04-11T13:15:32-04:00
4+
weight: 1
5+
draft: false
6+
description: "Learn about Docker image layering and why it is important."
7+
---
8+
9+
10+
Docker images are composed of layers, as shown in the diagram below. If you download
11+
the standard `weblogic:12.2.1.3` image from the [Docker Store](https://hub.docker.com/_/oracle-weblogic-server-12c),
12+
then you can see these layers using the command `docker inspect store/oracle/weblogic:12.2.1.3`
13+
(the domain layer will not be there). You are not required to use layers, but
14+
efficient use of layers is considered a best practice.
15+
16+
![Docker image layers](/weblogic-kubernetes-operator/images/layers.png)
17+
18+
#### Why is it important to maintain the layering of images?
19+
20+
Layering is an important technique in Docker images. Layers are important because they
21+
are shared between images. Let's consider an example. In the diagram below, we have
22+
two domains that we have built using layers. The second domain has some additional
23+
patches that we needed on top of those provided in the standard WebLogic image. Those
24+
are installed in their own layer, and then the second domain is created in another
25+
layer on top of that.
26+
27+
Let's assume we have a three-node Kubernetes cluster and we are running both domains
28+
in this cluster. Sooner or later, we will end up with servers in each domain running
29+
on each node, so eventually all of the image layers are going to be needed on all of
30+
the nodes. Using the approach shown below (that is, standard Docker layering techniques)
31+
we are going to need to store all six of these layers on each node. If you add up the
32+
sizes, then you will see that it comes out to about 1.5GB per node.
33+
34+
![Docker images with layers](/weblogic-kubernetes-operator/images/more-layers.png)
35+
36+
Now, let's consider the alternative, where we do not use layers, but instead,
37+
build images for each domain and put everything in one big layer (this is often
38+
called "squashing" the layers). In this case, we have the same content, but if
39+
you add up the size of the images, you get 2.9GB per node. That’s almost twice the size!
40+
41+
![Docker images without layers](/weblogic-kubernetes-operator/images/no-layers.png)
42+
43+
With only two domains, you start to see the problem. In the layered approach, each
44+
new domain is adding only a relatively very small increment. In the non-layered
45+
approach, each new domain is essentially adding the entire stack over again. Imagine
46+
if we had ten domains, now the calculation looks like this:
47+
48+
| | With Layers | Without Layers |
49+
| -------------------------- | ----------------- | ----------------- |
50+
| Shared Layers | 1.4GB | 0GB |
51+
| Dedicated/different layers | 10 x 10MB = 100MB | 10 x 1.5GB = 15GB |
52+
| Total per node | 1.5GB | 15GB |
53+
54+
55+
You can see how the amount of storage for images really starts to add up, and it
56+
is not just a question of storage. When Kubernetes creates a container from an
57+
image, the size of the image has an impact on how long it takes to create and
58+
start the container.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
title: "Mutate the domain layer"
3+
date: 2019-04-11T13:43:41-04:00
4+
draft: false
5+
weight: 4
6+
description: "How to mutate the domain layer."
7+
---
8+
9+
If you need to mutate the domain layer, and keep the same domain encryption keys,
10+
then there are some choices about how to implement that, as alluded to previously.
11+
Let's explore those in some more detail now.
12+
13+
The first option is to implement each mutation as a delta to the previous state.
14+
This is conceptually similar to how immutable objects (like Java Strings) are
15+
implemented, a "copy on write" approach applied to the domain configuration as a
16+
unit. This does have the advantage that it is simple to implement, but the
17+
disadvantage that your builds would depend on the previous good build and
18+
this is somewhat contrary to typical CI/CD practices. You also have to work
19+
out what to do with the bad builds, or "holes" in the sequence.
20+
21+
![Mutating the previous state](/weblogic-kubernetes-operator/images/n-1.png)
22+
23+
An alternative is to capture a "primordial state" of the domain before starting
24+
the sequence. In practical terms, this might mean creating a very simple domain
25+
with no applications or resources in it, and "saving" it before ever starting
26+
any servers. This primordial domain (let’s call it t=0) would then be used
27+
to build each mutation. So each state is built from t=0, plus all of the
28+
changes up to that point.
29+
30+
Said another way, each build would start with t=0 as the base image and extend it.
31+
This eliminates the need to keep each intermediate state, and would also likely
32+
have benefits when you remove things from the domain, because you would not have
33+
"lost" ("whited out" is the Docker layer term) space in the intermediate layers.
34+
Although, these layers tend to be relatively small, so this is possibly not a big issue.
35+
36+
![Rebuilding from a primordial state](/weblogic-kubernetes-operator/images/primordial.png)
37+
38+
This approach is probably an improvement. It does get interesting though when you
39+
update a lower layer, for example when you patch WebLogic or update the JDK. When
40+
this happens, you need to create another base image, shown in the diagram as v2 t-0.
41+
All of the mutations in this new chain are based on this new base image. So that
42+
still leaves us with the problem of how to take the domain from the first series
43+
(v1 t=0 to t=3) and "copy" it across to the second series (v2).
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
title: "Tools"
3+
date: 2019-04-11T13:50:15-04:00
4+
draft: false
5+
weight: 6
6+
description: "Tools that are available to build CI/CD pipelines."
7+
---
8+
9+
### WebLogic Deploy Tooling (WDT)
10+
11+
You can use several of the [WDT tools](https://github.com/oracle/weblogic-deploy-tooling)
12+
in a CI/CD pipeline. For example, the
13+
`createDomain` tool creates a new domain based on a simple model, and
14+
`updateDomain` (and `deployApps`) uses the same model concept to update
15+
an existing domain (preserving the same domain encryption key). The `deployApps`
16+
tool is very similar to the updateDomain tool, but limits what can be updated
17+
to application related configuration attributes such as data sources and
18+
application archives. The model used by these tools is a sparse set of
19+
attributes needed to create or update the domain. A model can be as sparse
20+
as providing only the WebLogic Server administrative password, although not very
21+
interesting. A good way to get a jumpstart on a model is to use the
22+
`discoverDomain` tool in WDT which builds a model based on an existing domain.
23+
24+
Other than the tools themselves, there are three components to the WDT tools:
25+
26+
- *The Domain Model* - Metadata model describing the desired domain.
27+
The metadata domain model can be YAML or JSON and is documented [here](https://github.com/oracle/weblogic-deploy-tooling#the-metadata-model).
28+
- *The Archive Zip* - Binaries to supplement the model.
29+
All binaries needed to supplement the model must be specified in an archive
30+
file, which is just a ZIP file with a specific directory structure. Optionally,
31+
the model can be stored inside the ZIP file, if desired. Any binaries not
32+
already on the target system must be in the ZIP file so that the tooling
33+
can extract them in the target domain.
34+
- *The Properties File* - A standard Java properties file.
35+
A property file used to provide values to placeholders in the model.
36+
37+
### WDT Create Domain Samples
38+
39+
- (Docker) A sample for creating a domain in a Docker image with WDT can be found
40+
[here](https://github.com/oracle/weblogic-deploy-tooling/tree/master/samples/docker-domain).
41+
- (Kubernetes) A similar sample of creating a domain in a Docker image with WDT
42+
can be found in the WebLogic Kubernetes Operator project for creating a
43+
[domain-in-image with WDT](https://oracle.github.io/weblogic-kubernetes-operator/samples/simple/domains/domain-home-in-image/).
44+
45+
### WebLogic Scripting Tool (WLST)
46+
47+
You can use WLST scripts to create and/or update domains in a CI/CD pipeline.
48+
We recommend that you use offline WLST for this purpose. There may be some
49+
scenarios where it is necessary to use WLST online, but we recommend that
50+
you do that only as an exception, and when absolutely necessary.
51+
52+
If you do not already have WLST scripts, we recommend that you consider
53+
using WebLogic Deploy Tooling (WDT) instead. It provides a more declarative
54+
approach to domain creation, whereas WLST is more of an imperative scripting
55+
language. WDT provides advantages like being able to use the same model with
56+
different versions of WebLogic, whereas you may need to update WLST scripts
57+
manually when migrating to a new version of WebLogic for example.
58+
59+
### WebLogic pack and unpack tools
60+
61+
WebLogic Server provides tools called "pack" and "unpack" that can be used to
62+
"clone" a domain. These tools do not preserve the domain encryption key.
63+
You can use these tools to make copies of domains in scenarios when you do
64+
not need the same domain encryption key.

0 commit comments

Comments
 (0)