Bring your own Apache Kafka® Connect cluster
Aiven provides Apache Kafka® Connect as a managed service in combination with the Aiven for Apache Kafka® managed service. However, there are circumstances where you may want to roll your own Kafka Connect cluster.
Integrate your own Apache Kafka Connect cluster with Aiven for Apache Kafka and use the schema registry offered by Karapace. The example below shows how to create a JDBC sink connector to a PostgreSQL® database.
Prerequisites
To bring your own Apache Kafka Connector, you need an Aiven for Apache Kafka service up and running.
For the JDBC sink connector database example, collect the following information about the Aiven for Apache Kafka service and the target database upfront:
APACHE_KAFKA_HOST: The hostname of the Apache Kafka serviceAPACHE_KAFKA_PORT: The port of the Apache Kafka serviceREST_API_PORT: The Apache Kafka's REST API port, only needed when testing data flow with REST APIsREST_API_USERNAME: The Apache Kafka's REST API username, only needed when testing data flow with REST APIsREST_API_PASSWORD: The Apache Kafka's REST API password, only needed when testing data flow with REST APIsSCHEMA_REGISTRY_PORT: The Apache Kafka's schema registry port, only needed when using Avro as data formatSCHEMA_REGISTRY_USER: The Apache Kafka's schema registry username, only needed when using Avro as data formatSCHEMA_REGISTRY_PASSWORD: The Apache Kafka's schema registry user password, only needed when using Avro as data formatPG_HOST: The PostgreSQL service hostnamePG_PORT: The PostgreSQL service portPG_USERNAME: The PostgreSQL service usernamePG_PASSWORD: The PostgreSQL service passwordPG_DATABASE_NAME: The PostgreSQL service database name
If you're using Aiven for PostgreSQL and Aiven for Apache Kafka the
above details are available in the Aiven
console service Overview tab or via the
dedicated avn service get command with the
Aiven CLI.
Attach your own Apache Kafka Connect cluster to Aiven for Apache Kafka®
The following example demonstrates how to setup a local Apache Kafka Connect cluster with a working JDBC sink connector and attach it to an Aiven for Apache Kafka service.
Set up the truststore and keystore
Create a Java keystore and truststore for the Aiven for Apache Kafka service. For the following example we assume:
- The keystore is available at
KEYSTORE_PATH/client.keystore.p12 - The truststore is available at
TRUSTSTORE_PATH/client.truststore.jks - For simplicity, the same secret (password) is used for both the
keystore and the truststore, and is shown as
KEY_TRUST_SECRET
Configure the Aiven for Apache Kafka service
Enable the schema registry features offered by Karapace. You can do it in the Aiven Console in the Aiven for Apache Kafka service Overview tab.
- Enable the Schema Registry (Karapace) and Apache Kafka REST API (Karapace)
- In the Topic tab, create a topic called
jdbc_sink, the topic will be used by the Apache Kafka Connect connector
Download the required binaries
The following binaries are needed to setup a Apache Kafka Connect cluster locally:
- Apache Kafka
- Aiven for Kafka connect JDBC connector
- If you are going to use Avro as the data format, Avro Value Converter. The examples below show how to do this.
Set up the local Apache Kafka Connect cluster
The following process defines the setup required to create a local Apache Kafka
Connect cluster with Apache Kafka 3.1.0, Avro converter 7.1.0 and JDBC
connector 6.7.0:
-
Extract the Apache Kafka binaries
tar -xzf kafka_2.13-3.1.0.tgz -
Within the newly created
kafka_2.13-3.1.0folder, create apluginsfolder containing alibsub-foldercd kafka_2.13-3.1.0mkdir -p plugins/lib -
Unzip the JDBC and Avro binaries and copy the
jarfiles in theplugins/libfolder# extract aiven connect jdbcunzip jdbc-connector-for-apache-kafka-6.7.0.zip# extract confluent kafka connect avro converterunzip confluentinc-kafka-connect-avro-converter-7.1.0.zip# copying plugins in the plugins/lib foldercp jdbc-connector-for-apache-kafka-6.7.0/*.jar plugins/lib/cp confluentinc-kafka-connect-avro-converter-7.1.0/*.jar plugins/lib/ -
Create a properties file,
my-connect-distributed.properties, under the mainkafka_2.13-3.1.0folder, for the Apache Kafka Connect settings. Change the following placeholders:PATH_TO_KAFKA_HOMEto the path to thekafka_2.13-3.1.0folderAPACHE_KAFKA_HOST,APACHE_KAFKA_PORT,SCHEMA_REGISTRY_PORT,SCHEMA_REGISTRY_USER,SCHEMA_REGISTRY_PASSWORD, to the related parameters fetched in the prerequisite stepKEYSTORE_PATH,TRUSTSTORE_PATHandKEY_TRUST_SECRETto the keystore, truststore location and related secret as defined in the related step
# Define the folders for plugins, including the JDBC and Avroplugin.path=PATH_TO_KAFKA_HOME/kafka_2.13-3.1.0/plugins# Defines the location of the Apache Kafka bootstrap serversbootstrap.servers=APACHE_KAFKA_HOST:APACHE_KAFKA_PORT# Defines the group.id used by the connection clustergroup.id=connect-cluster# Defines the input data format for key and value: JSON without schemakey.converter=org.apache.kafka.connect.json.JsonConvertervalue.converter=org.apache.kafka.connect.json.JsonConverterkey.converter.schemas.enable=falsevalue.converter.schemas.enable=false# Defines the internal data format for key and value: JSON without schemainternal.key.converter=org.apache.kafka.connect.json.JsonConverterinternal.value.converter=org.apache.kafka.connect.json.JsonConverterinternal.key.converter.schemas.enable=falseinternal.value.converter.schemas.enable=false# Connect clusters create three topics to manage offsets, configs, and status# information. Note that these contribute towards the total partition limit quota.offset.storage.topic=connect-offsetsoffset.storage.replication.factor=3offset.storage.partitions=3config.storage.topic=connect-configsconfig.storage.replication.factor=3status.storage.topic=connect-statusstatus.storage.replication.factor=3# Defines the flush interval for the offset comunicationoffset.flush.interval.ms=10000# Defines the SSL endpointssl.endpoint.identification.algorithm=httpsrequest.timeout.ms=20000retry.backoff.ms=500security.protocol=SSLssl.protocol=TLSssl.truststore.location=TRUSTSTORE_PATH/client.truststore.jksssl.truststore.password=KEY_TRUST_SECRETssl.keystore.location=KEYSTORE_PATH/client.keystore.p12ssl.keystore.password=KEY_TRUST_SECRETssl.key.password=KEY_TRUST_SECRETssl.keystore.type=PKCS12# Defines the consumer SSL endpointconsumer.ssl.endpoint.identification.algorithm=httpsconsumer.request.timeout.ms=20000consumer.retry.backoff.ms=500consumer.security.protocol=SSLconsumer.ssl.protocol=TLSconsumer.ssl.truststore.location=TRUSTSTORE_PATH/client.truststore.jksconsumer.ssl.truststore.password=KEY_TRUST_SECRETconsumer.ssl.keystore.location=KEYSTORE_PATH/client.keystore.p12consumer.ssl.keystore.password=KEY_TRUST_SECRETconsumer.ssl.key.password=KEY_TRUST_SECRETconsumer.ssl.keystore.type=PKCS12# Defines the producer SSL endpointproducer.ssl.endpoint.identification.algorithm=httpsproducer.request.timeout.ms=20000producer.retry.backoff.ms=500producer.security.protocol=SSLproducer.ssl.protocol=TLSproducer.ssl.truststore.location=TRUSTSTORE_PATH/client.truststore.jksproducer.ssl.truststore.password=KEY_TRUST_SECRETproducer.ssl.keystore.location=KEYSTORE_PATH/client.keystore.p12producer.ssl.keystore.password=KEY_TRUST_SECRETproducer.ssl.key.password=KEY_TRUST_SECRETproducer.ssl.keystore.type=PKCS12 -
Start the local Apache Kafka Connect cluster, executing the following from the
kafka_2.13-3.1.0folder:./bin/connect-distributed.sh ./my-connect-distributed.properties
Add the JDBC sink connector
To add a JDBC connector to the local Apache Kafka Connect cluster:
-
Create the JDBC sink connector JSON configuration file named
jdbc-sink-pg.jsonwith the following content, replacing the placeholdersPG_HOST,PG_PORT,PG_USERNAME,PG_PASSWORD,PG_DATABASE_NAME,APACHE_KAFKA_HOST,SCHEMA_REGISTRY_PORT,SCHEMA_REGISTRY_USER,SCHEMA_REGISTRY_PASSWORD.{"name": "jdbc-sink-pg","config": {"connector.class": "io.aiven.connect.jdbc.JdbcSinkConnector","connection.url": "jdbc:postgresql://PG_HOST:PG_PORT/PG_DATABASE_NAME?user=PG_USERNAME&password=PG_PASSWORD&ssl=required","tasks.max": "1","topics": "jdbc_sink","auto.create": "true","value.converter": "io.confluent.connect.avro.AvroConverter","value.converter.schema.registry.url": "https://APACHE_KAFKA_HOST:SCHEMA_REGISTRY_PORT","value.converter.basic.auth.credentials.source": "USER_INFO","value.converter.basic.auth.user.info": "SCHEMA_REGISTRY_USER:SCHEMA_REGISTRY_PASSWORD"}} -
Create the JDBC sink connector instance using Kafka Connect REST APIs
curl -s -H "Content-Type: application/json" -X POST \-d @jdbc-sink-pg.json \http://localhost:8083/connectors/ -
Check the status of the JDBC sink connector instance,
jqis used to beautify the outputcurl localhost:8083/connectors/jdbc-sink-pg/status | jqThe result should be similar to the following
{"name": "jdbc-sink-pg","connector": {"state": "RUNNING","worker_id": "10.128.0.12:8083"},"tasks": [{"id": 0,"state": "RUNNING","worker_id": "10.128.0.12:8083"}],"type": "sink"}
Check the dedicated blog post for an end-to-end example of how to setup a Kafka Connect cluster to host a custom connector.
Verify the JDBC connector using Karapace REST APIs
To verify that the connector is working, you can write messages to the
jdbc_sink topic in Avro format using Karapace REST
APIs:
-
Create a Avro schema using the
/subjects/endpoint, after changing the placeholders forREST_API_USER,REST_API_PASSWORD,APACHE_KAFKA_HOST,REST_API_PORTcurl -X POST -H "Content-Type: application/vnd.schemaregistry.v1+json" \--data '''{"schema":"{\"type\": \"record\",\"name\": \"jdbcsinkexample\",\"namespace\": \"example\",\"doc\": \"example\",\"fields\": [{ \"type\": \"string\", \"name\": \"name\", \"doc\": \"person name\", \"namespace\": \"example\", \"default\": \"mario\"},{ \"type\": \"int\", \"name\": \"age\", \"doc\": \"persons age\", \"namespace\": \"example\", \"default\": 5}]}"}''' \https://REST_API_USER:REST_API_PASSWORD@APACHE_KAFKA_HOST:REST_API_PORT/subjects/jdbcsinkexample/versions/The above call creates a new schema called
jdbcsinkexamplewith a schema containing two fields (nameandage). -
Create a message in the
jdbc_sinktopic using thejdbcsinkexampleschema, after changing the placeholders forREST_API_USER,REST_API_PASSWORD,APACHE_KAFKA_HOST,REST_API_PORTcurl -H "Content-Type: application/vnd.kafka.avro.v2+json" -X POST \-d '''{"value_schema":"{\"namespace\": \"test\", \"type\": \"record\", \"name\": \"example\", \"fields\": [{\"name\": \"name\", \"type\": \"string\"},{\"name\": \"age\", \"type\": \"int\"}]}","records": [{"value": {"name": "Eric","age":77}}]}''' \https://REST_API_USER:REST_API_PASSWORD@APACHE_KAFKA_HOST:REST_API_PORT/topics/jdbc_sink -
Verify the presence of a table called
jdbc_sinkin PostgreSQL containing the row with nameEricand age77