Skip to content

Commit f20706d

Browse files
Run in docker and kubernetes
1 parent ce2dd16 commit f20706d

File tree

3 files changed

+151
-3
lines changed

3 files changed

+151
-3
lines changed

Dockerfile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
FROM ibmcom/eventstreams-kafka-ce-icp-linux-amd64:2019.2.1-3a2f93e as builder
2+
3+
4+
FROM ibmjava:8-jre
5+
6+
RUN addgroup --gid 5000 --system esgroup && \
7+
adduser --uid 5000 --ingroup esgroup --system esuser
8+
9+
COPY --chown=esuser:esgroup --from=builder /opt/kafka/bin/ /opt/kafka/bin/
10+
COPY --chown=esuser:esgroup --from=builder /opt/kafka/libs/ /opt/kafka/libs/
11+
COPY --chown=esuser:esgroup --from=builder /opt/kafka/config/connect-distributed.properties /opt/kafka/config/
12+
COPY --chown=esuser:esgroup --from=builder /opt/kafka/config/connect-log4j.properties /opt/kafka/config/
13+
RUN mkdir /opt/kafka/logs && chown esuser:esgroup /opt/kafka/logs
14+
COPY --chown=esuser:esgroup target/kafka-connect-mq-source-1.1.0-jar-with-dependencies.jar /opt/kafka/libs/
15+
16+
WORKDIR /opt/kafka
17+
18+
EXPOSE 8083
19+
20+
USER esuser
21+
22+
ENTRYPOINT ["./bin/connect-distributed.sh", "config/connect-distributed.properties"]

README.md

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ The connector is supplied as source code which you can easily build into a JAR f
99

1010
- [Building the connector](#building-the-connector)
1111
- [Running the connector](#running-the-connector)
12+
- [Running the connector with Docker](#running-with-docker)
13+
- [Deploying the connector to Kubernetes](#deploying-to-kubernetes)
1214
- [Data formats](#data-formats)
1315
- [Security](#security)
1416
- [Performance and syncpoint limit](#performance-and-syncpoint-limit)
@@ -67,6 +69,43 @@ To run the connector in standalone mode from the directory into which you instal
6769
bin/connect-standalone.sh connect-standalone.properties mq-source.properties
6870
```
6971

72+
## Running with Docker
73+
74+
This repository includes a Dockerfile to run Kafka Connect in distributed mode. It also adds in the MQ Source Connector as an available connector plugin. It uses the default connect-distributed.properties and connect-log4j.properties files.
75+
76+
1. `mvn clean package`
77+
1. `docker build -t kafkaconnect-with-mq-source:0.0.1 .`
78+
1. `docker run -p 8083:8083 kafkaconnect-with-mq-source:0.0.1`
79+
80+
**NOTE:** To provide custom properties files create a folder called `config` containing the `connect-distributed.properties` and `connect-log4j.properties` files and use a Docker volume to make them available when running the container:
81+
`docker run -v $(pwd)/config:/opt/kafka/config -p 8083:8083 kafkaconnect:0.0.1`
82+
83+
## Deploying to Kubernetes
84+
85+
This repository includes a Kubernetes yaml file called `kafka-connect.yaml`. This will create a deployment to run Kafka Connect in distributed mode and a service to access the deployment.
86+
87+
The deployment assumes the existence of a Secret called `connect-distributed-config` and a ConfigMap called `connect-log4j-config`. These can be created using the default files in your Kafka install, however it is easier to edit them later if comments and whitespaces are trimmed before creation.
88+
89+
### Creating Kafka Connect configuration Secret and ConfigMap
90+
91+
Create Secret for Kafka Connect configuration:
92+
1. `cp kafka/config/connect-distributed.properties connect-distributed.properties.orig`
93+
1. `sed '/^#/d;/^[[:space:]]*$/d' < connect-distributed.properties.orig > connect-distributed.properties`
94+
1. `kubectl -n <namespace> create secret connect-distributed-config --from-file=connect-distributed.properties`
95+
96+
Create ConfigMap for Kafka Connect Log4j configuration:
97+
1. `cp kafka/config/connect-log4j.properties connect-log4j.properties.orig`
98+
1. `sed '/^#/d;/^[[:space:]]*$/d' < connect-log4j.properties.orig > connect-log4j.properties`
99+
1. `kubectl -n <namespace> create configmap connect-log4j-config --from-file=connect-log4j.properties`
100+
101+
### Creating Kafka Connect deployment and service in Kubernetes
102+
103+
**NOTE:** Remember to [build the Docker image](#running-with-docker) and push it to your Kubernetes image repository. You might need to update the image name in the `kafka-connect.yaml` file.
104+
105+
1. Update the namespace in `kafka-connect.yaml`
106+
1. `kubectl -n <namespace> apply -f kafka-connect.yaml`
107+
1. `curl <serviceIP>:<servicePort>/connector-plugins` to see the MQ Source connector available to use
108+
70109
## Data formats
71110
Kafka Connect is very flexible but it's important to understand the way that it processes messages to end up with a reliable system. When the connector encounters a message that it cannot process, it stops rather than throwing the message away. Therefore, you need to make sure that the configuration you use can handle the messages the connector will process.
72111

@@ -78,7 +117,7 @@ When the MQ source connector reads a message from MQ, it chooses a schema to rep
78117

79118
There are two record builders supplied with the connector, although you can write your own. The basic rule is that if you just want the message to be passed along to Kafka unchanged, the default record builder is probably the best choice. If the incoming data is in JSON format and you want to use a schema based on its structure, use the JSON record builder.
80119

81-
There are three converters built into Apache Kafka. You need to make sure that the incoming message format, the setting of the *mq.message.body.jms* configuration, the record builder and converter are all compatible. By default, everything is just treated as bytes but if you want the connector to understand the message format and apply more sophisticated processing such as single-message transforms, you'll need a more complex configuration. The following table shows the basic options that work.
120+
There are three converters built into Apache Kafka. You need to make sure that the incoming message format, the setting of the `mq.message.body.jms` configuration, the record builder and converter are all compatible. By default, everything is just treated as bytes but if you want the connector to understand the message format and apply more sophisticated processing such as single-message transforms, you'll need a more complex configuration. The following table shows the basic options that work.
82121

83122
| Record builder class | Incoming MQ message | mq.message.body.jms | Converter class | Outgoing Kafka message |
84123
| ------------------------------------------------------------------- | ---------------------- | ------------------- | ------------------------------------------------------ | ----------------------- |
@@ -129,16 +168,20 @@ You must then choose a converter than can handle the value schema and class. The
129168
| org.apache.kafka.connect.json.JsonConverter | Base-64 JSON String | JSON String | **JSON data** |
130169

131170
### Key support and partitioning
132-
By default, the connector does not use keys for the Kafka messages it publishes. It can be configured to use the JMS message headers to set the key of the Kafka records. You could use this, for example, to use the MQMD correlation identifier as the partitioning key when the messages are published to Kafka. There are three valid values for the `mq.record.builder.key.header` that controls this behavior.
171+
By default, the connector does not use keys for the Kafka messages it publishes. It can be configured to use the JMS message headers to set the key of the Kafka records. You could use this, for example, to use the MQMD correlation identifier as the partitioning key when the messages are published to Kafka. There are four valid values for the `mq.record.builder.key.header` that controls this behavior.
133172

134173
| mq.record.builder.key.header | Key schema | Key class | Recommended value for key.converter |
135174
| ---------------------------- |---------------- | --------- | ------------------------------------------------------ |
136175
| JMSMessageID | OPTIONAL_STRING | String | org.apache.kafka.connect.storage.StringConverter |
137176
| JMSCorrelationID | OPTIONAL_STRING | String | org.apache.kafka.connect.storage.StringConverter |
138177
| JMSCorrelationIDAsBytes | OPTIONAL_BYTES | byte[] | org.apache.kafka.connect.converters.ByteArrayConverter |
178+
| JMSDestination | OPTIONAL_STRING | String | org.apache.kafka.connect.storage.StringConverter |
139179

140180
In MQ, the message ID and correlation ID are both 24-byte arrays. As strings, the connector represents them using a sequence of 48 hexadecimal characters.
141181

182+
### Accessing MQMD fields
183+
If you write your own RecordBuilder, you can access the MQMD fields of the MQ messages as JMS message properties. By default, only a subset of the MQMD fields are available, but you can get access to all of them by setting the configuration `mq.message.mqmd.read`. For more information, see [JMS message object properties](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.1.0/com.ibm.mq.dev.doc/q032350_.htm) in the MQ documentation.
184+
142185

143186
## Security
144187
The connector supports authentication with user name and password and also connections secured with TLS using a server-side certificate and mutual authentication with client-side certificates.
@@ -170,10 +213,11 @@ The configuration options for the Kafka Connect source connector for IBM MQ are
170213
| mq.ccdt.url | The URL for the CCDT file containing MQ connection details | string | | URL for obtaining a CCDT file |
171214
| mq.record.builder | The class used to build the Kafka Connect record | string | | Class implementing RecordBuilder |
172215
| mq.message.body.jms | Whether to interpret the message body as a JMS message type | boolean | false | |
173-
| mq.record.builder.key.header | The JMS message header to use as the Kafka record key | string | | JMSMessageID, JMSCorrelationID, JMSCorrelationIDAsBytes |
216+
| mq.record.builder.key.header | The JMS message header to use as the Kafka record key | string | | JMSMessageID, JMSCorrelationID, JMSCorrelationIDAsBytes, JMSDestination |
174217
| mq.ssl.cipher.suite | The name of the cipher suite for TLS (SSL) connection | string | | Blank or valid cipher suite |
175218
| mq.ssl.peer.name | The distinguished name pattern of the TLS (SSL) peer | string | | Blank or DN pattern |
176219
| mq.batch.size | The maximum number of messages in a batch (unit of work) | integer | 250 | 1 or greater |
220+
| mq.message.mqmd.read | Whether to enable reading of all MQMD fields | boolean | false | |
177221
| topic | The name of the target Kafka topic | string | | Topic name |
178222

179223
### Using a CCDT file
@@ -204,6 +248,10 @@ Update the connector configuration file to reference `secret-key` in the file:
204248
mq.password=${file:mq-secret.properties:secret-key}
205249
```
206250

251+
##### Using FileConfigProvider in Kubernetes
252+
253+
To use a file for the `mq.password` in Kubernetes, you create a Secret using the file as described in [the Kubernetes docs](https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-files-from-a-pod).
254+
207255
## Troubleshooting
208256

209257
### Unable to connect to Kafka

kafka-connect.yaml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Deployment
2+
apiVersion: apps/v1
3+
kind: Deployment
4+
metadata:
5+
name: kafkaconnect-deploy
6+
labels:
7+
app: kafkaconnect-with-mq-source
8+
spec:
9+
replicas: 1
10+
selector:
11+
matchLabels:
12+
app: kafkaconnect-with-mq-source
13+
template:
14+
metadata:
15+
namespace: <namespace>
16+
labels:
17+
app: kafkaconnect-with-mq-source
18+
spec:
19+
securityContext:
20+
runAsNonRoot: true
21+
runAsUser: 5000
22+
containers:
23+
- name: kafkaconnect-container
24+
image: kafkaconnect-with-mq-source:0.0.1
25+
readinessProbe:
26+
httpGet:
27+
path: /
28+
port: 8083
29+
httpHeaders:
30+
- name: Accept
31+
value: '*/*'
32+
failureThreshold: 2
33+
initialDelaySeconds: 5
34+
periodSeconds: 10
35+
successThreshold: 1
36+
timeoutSeconds: 2
37+
livenessProbe:
38+
httpGet:
39+
path: /
40+
port: 8083
41+
httpHeaders:
42+
- name: Accept
43+
value: '*/*'
44+
initialDelaySeconds: 20
45+
periodSeconds: 20
46+
ports:
47+
- containerPort: 8083
48+
volumeMounts:
49+
- name: connect-config
50+
mountPath: /opt/kafka/config/connect-distributed.properties
51+
subPath: connect-distributed.properties
52+
- name: connect-log4j
53+
mountPath: /opt/kafka/config/connect-log4j.properties
54+
subPath: connect-log4j.properties
55+
volumes:
56+
- name: connect-config
57+
secret:
58+
secretName: connect-distributed-config
59+
- name: connect-log4j
60+
configMap:
61+
name: connect-log4j-config
62+
63+
---
64+
# Service
65+
apiVersion: v1
66+
kind: Service
67+
metadata:
68+
name: kafkaconnect-service
69+
labels:
70+
app: kafkaconnect-service
71+
spec:
72+
type: NodePort
73+
ports:
74+
- name: kafkaconnect
75+
protocol: TCP
76+
port: 8083
77+
selector:
78+
app: kafkaconnect-with-mq-source

0 commit comments

Comments
 (0)