{"id":1220,"date":"2022-01-23T09:41:42","date_gmt":"2022-01-23T16:41:42","guid":{"rendered":"https:\/\/bullyrooks.com\/?p=1220"},"modified":"2022-01-23T09:43:13","modified_gmt":"2022-01-23T16:43:13","slug":"cloud-kube-pt2-setting-up-a-datastore","status":"publish","type":"post","link":"https:\/\/bullyrooks.com\/index.php\/2022\/01\/23\/cloud-kube-pt2-setting-up-a-datastore\/","title":{"rendered":"Cloud Kube Pt2 | Setting Up a Datastore"},"content":{"rendered":"\n<p>The <a href=\"https:\/\/bullyrooks.com\/index.php\/2022\/01\/02\/kubernetes-application-hosted-in-the-cloud\/\" data-type=\"post\" data-id=\"1141\">first part of these courses<\/a> was all about setting up an build and deploy pipeline so that we could automate building a helm chart and deploying to our cloud hosted environment at Okteto.<\/p>\n\n\n\n<p>In this course we&#8217;re going to start adding more functionality so that we can demonstrate best practices around testing, logging, messaging and tracing.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Updates<\/h2>\n\n\n\n<p>At this point, you may need to make some upates in order to get mongodb working with springboot.  <a href=\"https:\/\/www.mongodb.com\/community\/forums\/t\/sslhandshakeexception-should-not-be-presented-in-certificate-request\/12493\">It appears that you need java sdk 13.0.2 (at least) in order to get spring boot to communicate with mongodb<\/a>.  You&#8217;ll also need to update your intellij and dockerfile as well.  Here&#8217;s the new dockerfile configuration<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># syntax=docker\/dockerfile:experimental\nFROM openjdk:<span class=\"has-inline-color has-vivid-red-color\">15.0.2-slim-buster<\/span> as build\n\nCOPY .mvn .mvn\nCOPY mvnw .\nCOPY pom.xml .\n\n<span class=\"has-inline-color has-vivid-red-color\"># download dependencies\nRUN .\/mvnw dependency:go-offline<\/span>\n\nCOPY src src\n\n# Setup the maven cache\nRUN --mount=type=cache,target=\/root\/.m2,rw .\/mvnw -B package -DskipTests\n\nFROM openjdk:<span class=\"has-inline-color has-vivid-red-color\">15.0.2-slim-buster<\/span>\nCOPY --from=build target\/*.jar app.jar\nENTRYPOINT &#91;\"java\", \"-jar\", \"app.jar\"]\n<\/code><\/pre>\n\n\n\n<p>I updated all the way up to 15.0.2, but I only use java 11 features so the maven pom doesn&#8217;t need to be updated.<\/p>\n\n\n\n<p>You can see that I also added a layer to retrieve dependencies in offline mode.  I am not sure this helps because the cache should already do this, but doesn&#8217;t hurt.<\/p>\n\n\n\n<p>Additionally, I didn&#8217;t like the image name as <code>cloud_application <\/code>instead of <code>cloud-application<\/code>.  So I updated the github workflows to use my new name.  If you make this change, you&#8217;ll need to update your helm values.yaml to pull the correct image down (and create the repo in canister.io with the preferred name)<\/p>\n\n\n\n<p>main.yml<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>      - name: Extract metadata (tags, labels) for Docker\n        id: meta\n        uses: docker\/metadata-action@v3\n        with:\n          images: cloud.canister.io:5000\/bullyrooks\/<span class=\"has-inline-color has-vivid-red-color\">cloud-application<\/span>\n          #setting value manually, but could come from git tag\n          tags: |\n            type=ref,event=tag\n...\n      - name: Build and push\n        id: docker_build\n        uses: docker\/build-push-action@v2\n        with:\n          context: .\n          push: true\n          tags: |\n            cloud.canister.io:5000\/bullyrooks\/<span class=\"has-inline-color has-vivid-red-color\">cloud-application<\/span>:${{ env.VERSION }}\n          cache-from: type=local,src=\/tmp\/.buildx-cache\n          cache-to: type=local,mode=max,dest=\/tmp\/.buildx-cache-new\n...\n      - name: Deploy\n        uses: WyriHaximus\/github-action-helm3@v2\n        with:\n          exec: |\n            helm repo add bullyrooks https:\/\/bullyrooks.github.io\/helm-charts\/\n            helm repo update\n            helm upgrade cloud-application bullyrooks\/<span class=\"has-inline-color has-vivid-red-color\">cloud-application<\/span> --install\n          kubeconfig: '${{ secrets.KUBECONFIG }}'<\/code><\/pre>\n\n\n\n<p>values.yml<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>image:\n  repository: cloud.canister.io:5000\/bullyrooks\/<span class=\"has-inline-color has-vivid-red-color\">cloud-application<\/span>\n  pullPolicy: Always<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Create a Datastore<\/h2>\n\n\n\n<p>We&#8217;re going to setup a free mongodb cloud instance.  Go to the <a href=\"https:\/\/cloud.mongodb.com\">mongodb site<\/a> and create an account.  As you verify and create your account, make sure that you select Shared cloud database.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"318\" height=\"607\" src=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-37.png?resize=318%2C607&#038;ssl=1\" alt=\"\" class=\"wp-image-1221\" srcset=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-37.png?w=318&amp;ssl=1 318w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-37.png?resize=157%2C300&amp;ssl=1 157w\" sizes=\"auto, (max-width: 318px) 100vw, 318px\" data-recalc-dims=\"1\" \/><\/figure>\n\n\n\n<p>Choose AWS, use-east-1 and the rest of the defaults.  I change the cluster name to <code>bullyrooks<\/code>.<\/p>\n\n\n\n<p>For Security, use username and password.  Choose a username and password and click <code>Create User<\/code><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"804\" height=\"516\" src=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-38.png?resize=804%2C516&#038;ssl=1\" alt=\"\" class=\"wp-image-1222\" srcset=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-38.png?w=804&amp;ssl=1 804w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-38.png?resize=300%2C193&amp;ssl=1 300w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-38.png?resize=768%2C493&amp;ssl=1 768w\" sizes=\"auto, (max-width: 804px) 100vw, 804px\" data-recalc-dims=\"1\" \/><\/figure>\n\n\n\n<p>For connection, leave <code>My Local Environment<\/code> and click <code>Add My Current IP Address<\/code>.  Also, add 0.0.0.0\/0 (should allow all access), which will be needed for okteto to connect.  Then hit Finish and Close.  You&#8217;ll have to wait for the cluster to be created.  If you click on <code>Connect<\/code>, choose <code>Connect your Application<\/code>, then change <code>Driver <\/code>to <code>Java <\/code>and <code>Version <\/code>to <code>4.3 or later<\/code>, you&#8217;ll see the connection string that you&#8217;ll need to connect to this instance.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"748\" height=\"482\" src=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-39.png?resize=748%2C482&#038;ssl=1\" alt=\"\" class=\"wp-image-1223\" srcset=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-39.png?w=748&amp;ssl=1 748w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-39.png?resize=300%2C193&amp;ssl=1 300w\" sizes=\"auto, (max-width: 748px) 100vw, 748px\" data-recalc-dims=\"1\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Create the Repository Code<\/h2>\n\n\n\n<p>Checkout a new branch from <code>main<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git checkout -b database<\/code><\/pre>\n\n\n\n<p>Add the mongodb database starter to your pom.xml in the dependencies section<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>        &lt;dependency&gt;\n            &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n            &lt;artifactId&gt;spring-boot-starter-data-mongodb&lt;\/artifactId&gt;\n        &lt;\/dependency&gt;<\/code><\/pre>\n\n\n\n<p>Create these new packages under com.bullyrooks.cloud_application <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>com.bullyrooks.cloud_application.repository\ncom.bullyrooks.cloud_application.repository.document\ncom.bullyrooks.cloud_application.repository.mapper<\/code><\/pre>\n\n\n\n<p>Create a new class under <code>document <\/code>called <code>MessageDocument<\/code>.  Add this content<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.bullyrooks.cloud_application.repository.document;\n\nimport lombok.Data;\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.mongodb.core.mapping.Document;\n\n@Document(\"messages\")\n@Data\npublic class MessageDocument {\n    @Id\n    private String messageId;\n    private String firstName;\n    private String lastName;\n    private String message;\n}<\/code><\/pre>\n\n\n\n<p>Now create an interface called <code>MessageRepository <\/code>under <code>com.bu<\/code>llyrooks.cloud_application.repository.  Add this content<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.bullyrooks.cloud_application.repository;\n\nimport com.bullyrooks.cloud_application.repository.document.MessageDocument;\nimport org.springframework.data.mongodb.repository.MongoRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface MessageRepository extends MongoRepository&lt;MessageDocument, String&gt; {\n\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Create the Controller Code<\/h2>\n\n\n\n<p>We&#8217;re going to be using mapstruct again to help create the mappers needed to support a ports and adapters design.  Add this to your pom.xml<br>\/code<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">    &lt;properties&gt;\n        &lt;java.version&gt;11&lt;\/java.version&gt;\n        &lt;org.mapstruct.version&gt;1.4.1.Final&lt;\/org.mapstruct.version&gt;\n    &lt;\/properties&gt;\n\n...\n\n&lt;!-- mapstruct --&gt;\n&lt;dependency&gt;\n    &lt;groupId&gt;org.mapstruct&lt;\/groupId&gt;\n    &lt;artifactId&gt;mapstruct&lt;\/artifactId&gt;\n    &lt;version&gt;${org.mapstruct.version}&lt;\/version&gt;\n&lt;\/dependency&gt;\n&lt;dependency&gt;\n    &lt;groupId&gt;org.mapstruct&lt;\/groupId&gt;\n    &lt;artifactId&gt;mapstruct-processor&lt;\/artifactId&gt;\n    &lt;version&gt;${org.mapstruct.version}&lt;\/version&gt;\n&lt;\/dependency&gt;<\/pre>\n\n\n\n<p>Create a <code>dto <\/code>package in the <code>controller <\/code>package and put two classes in there.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.bullyrooks.cloud_application.controller.dto;\n\nimport lombok.Data;\n\n@Data\npublic class CreateMessageRequestDTO {\n    private String firstName;\n    private String lastName;\n    private String message;\n}\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.bullyrooks.cloud_application.controller.dto;\n\nimport lombok.Data;\n\n@Data\npublic class CreateMessageResponseDTO {\n    private String firstName;\n    private String lastName;\n    private String message;\n}\n<\/code><\/pre>\n\n\n\n<p>Create a package called <code>mapper <\/code>under <code>controller <\/code>and put these two classes there<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.bullyrooks.cloud_application.controller.mapper;\n\nimport com.bullyrooks.cloud_application.controller.dto.CreateMessageRequestDTO;\nimport com.bullyrooks.cloud_application.service.model.Message;\nimport org.mapstruct.Mapper;\nimport org.mapstruct.factory.Mappers;\n\n@Mapper\npublic interface CreateMessageRequestDTOMapper {\n    CreateMessageRequestDTOMapper INSTANCE = Mappers.getMapper(CreateMessageRequestDTOMapper.class);\n\n    Message dtoToModel(CreateMessageRequestDTO userAccountEntity);\n\n}\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.bullyrooks.cloud_application.controller.mapper;\n\nimport com.bullyrooks.cloud_application.controller.dto.CreateMessageRequestDTO;\nimport com.bullyrooks.cloud_application.controller.dto.CreateMessageResponseDTO;\nimport com.bullyrooks.cloud_application.service.model.Message;\nimport org.mapstruct.Mapper;\nimport org.mapstruct.factory.Mappers;\n\n@Mapper\npublic interface CreateMessageResponseDTOMapper {\n    CreateMessageResponseDTOMapper INSTANCE = Mappers.getMapper(CreateMessageResponseDTOMapper.class);\n\n    CreateMessageResponseDTO modelToDTO(Message message);\n\n}\n<\/code><\/pre>\n\n\n\n<p>Create a new class under controller and put this code there<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.bullyrooks.cloud_application.controller;\n\nimport com.bullyrooks.cloud_application.controller.dto.CreateMessageRequestDTO;\nimport com.bullyrooks.cloud_application.controller.dto.CreateMessageResponseDTO;\nimport com.bullyrooks.cloud_application.controller.dto.HelloWorldResponse;\nimport com.bullyrooks.cloud_application.controller.mapper.CreateMessageRequestDTOMapper;\nimport com.bullyrooks.cloud_application.controller.mapper.CreateMessageResponseDTOMapper;\nimport com.bullyrooks.cloud_application.service.MessageService;\nimport com.bullyrooks.cloud_application.service.model.Message;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\n@Slf4j\npublic class MessageController {\n\n    @Autowired\n    MessageService messageService;\n\n    @PostMapping(\"\/message\")\n    public CreateMessageResponseDTO createMessage(@RequestBody CreateMessageRequestDTO request){\n        log.info(\"createMessage : {}\", request);\n        Message message = CreateMessageRequestDTOMapper.INSTANCE.dtoToModel(request);\n        Message response = messageService.saveMessage(message);\n        return CreateMessageResponseDTOMapper.INSTANCE.modelToDTO(response);\n    }\n\n}\n<\/code><\/pre>\n\n\n\n<p>What we&#8217;re doing here is defining a request and response data transformation object (dto) and mapping the dto into our internal representation to align with ports and adapters design.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Create the Service Code<\/h2>\n\n\n\n<p>Make this package:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>com.bullyrooks.cloud_application.service.model\n<\/code><\/pre>\n\n\n\n<p>In the model package create this class<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.bullyrooks.cloud_application.service.model;\n\nimport lombok.Data;\n\n@Data\npublic class Message {\n    private String messageId;\n    private String firstName;\n    private String lastName;\n    private String message;\n}\n<\/code><\/pre>\n\n\n\n<p>Create this class in the service package<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.bullyrooks.cloud_application.service;\n\nimport com.bullyrooks.cloud_application.repository.MessageRepository;\nimport com.bullyrooks.cloud_application.repository.document.MessageDocument;\nimport com.bullyrooks.cloud_application.repository.mapper.MessageDocumentMapper;\nimport com.bullyrooks.cloud_application.service.model.Message;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n@Service\n@Slf4j\npublic class MessageService {\n\n    @Autowired\n    MessageRepository messageRepository;\n\n    public Message saveMessage(Message message){\n        MessageDocument msgDoc = MessageDocumentMapper.INSTANCE.modelToDocument(message);\n        log.info(\"saving document: {}\", msgDoc);\n        MessageDocument returnDoc = messageRepository.save(msgDoc);\n        return MessageDocumentMapper.INSTANCE.documentToModel(returnDoc);\n    }\n}\n\n<\/code><\/pre>\n\n\n\n<p>Here we&#8217;re creating our actual service logic, but we&#8217;ll need to also create our mappers to the documents<\/p>\n\n\n\n<p>Create this class in a package called <code>com.bullyrooks.cloud_application.repository.mapper<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.bullyrooks.cloud_application.repository.mapper;\n\nimport com.bullyrooks.cloud_application.repository.document.MessageDocument;\nimport com.bullyrooks.cloud_application.service.model.Message;\nimport org.mapstruct.Mapper;\nimport org.mapstruct.factory.Mappers;\n\n@Mapper\npublic interface MessageDocumentMapper {\n    MessageDocumentMapper INSTANCE = Mappers.getMapper(MessageDocumentMapper.class);\n\n    MessageDocument modelToDocument(Message model);\n\n    Message documentToModel(MessageDocument returnDoc);\n}\n\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Set Configuration<\/h2>\n\n\n\n<p>Create an <code>application.yml<\/code> file and add this code (or whatever matches your database configuration)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>spring:\n  application:\n    name: cloud_application\n  data:\n    mongodb:\n      uri: mongodb+srv:\/\/bullyrooks:${mongodb.password}@bullyrooks.4zqpz.mongodb.net\/bullyrooks?retryWrites=true&amp;w=majority\n<\/code><\/pre>\n\n\n\n<p>And update your application run configuration in Intellij to insert your password.<\/p>\n\n\n\n<p>you will also need <code>-Djdk.tls.client.protocols=TLSv1.2<\/code> to connect to mongodb<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"620\" src=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-40-1024x661.png?resize=960%2C620&#038;ssl=1\" alt=\"\" class=\"wp-image-1225\" srcset=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-40.png?resize=1024%2C661&amp;ssl=1 1024w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-40.png?resize=300%2C194&amp;ssl=1 300w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-40.png?resize=768%2C496&amp;ssl=1 768w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-40.png?w=1041&amp;ssl=1 1041w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" data-recalc-dims=\"1\" \/><\/figure>\n\n\n\n<p>Start up your application.  You should see it start and connect to mongodb<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>: Tomcat started on port(s): 8080 (http) with context path ''\n2022-01-17 14:51:12.388  INFO 23840 --- &#91;  restartedMain] c.b.cloud_application.CloudApplication   : Started CloudApplication in 2.109 seconds (JVM running for 2.993)\n2022-01-17 14:51:12.618  INFO 23840 --- &#91;ngodb.net:27017] org.mongodb.driver.connection            : Opened connection &#91;connectionId{localValue:4, serverValue:305244}] to bullyrooks-shard-00-01.4zqpz.mongodb.net:27017\n2022-01-17 14:51:12.618  INFO 23840 --- &#91;ngodb.net:27017] org.mongodb.driver.connection            : Opened connection &#91;connectionId{localValue:5, serverValue:7709}] to bullyrooks-shard-00-02.4zqpz.mongodb.net:27017\n2022-01-17 14:51:12.618  INFO 23840 --- &#91;ngodb.net:27017] org.mongodb.driver.connection            : Opened connection &#91;connectionId{localValue:3, serverValue:305292}] to bullyrooks-shard-00-01.4zqpz.mongodb.net:27017\n2022-01-17 14:51:12.618  INFO 23840 --- &#91;ngodb.net:27017] org.mongodb.driver.connection            : Opened connection &#91;connectionId{localValue:2, serverValue:300367}] to bullyrooks-shard-00-00.4zqpz.mongodb.net:27017\n2022-01-17 14:51:12.618  INFO 23840 --- &#91;ngodb.net:27017] org.mongodb.driver.connection            : Opened connection &#91;connectionId{localValue:1, serverValue:300367}] to bullyrooks-shard-00-00.4zqpz.mongodb.net:27017\n2022-01-17 14:51:12.618  INFO 23840 --- &#91;ngodb.net:27017] org.mongodb.driver.connection            : Opened connection &#91;connectionId{localValue:6, serverValue:7709}] to bullyrooks-shard-00-02.4zqpz.mongodb.net:27017\n2022-01-17 14:51:12.619  INFO 23840 --- &#91;ngodb.net:27017] org.mongodb.driver.cluster               : Monitor thread successfully connected to server with description ServerDescription{address=bullyrooks-shard-00-02.4zqpz.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=9, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=270532600, setName='atlas-x20br4-shard-0', canonicalAddress=bullyrooks-shard-00-02.4zqpz.mongodb.net:27017, hosts=&#91;bullyrooks-shard-00-02.4zqpz.mongodb.net:27017, bullyrooks-shard-00-01.4zqpz.mongodb.net:27017, bullyrooks-shard-00-00.4zqpz.mongodb.net:27017], passives=&#91;], arbiters=&#91;], primary='bullyrooks-shard-00-01.4zqpz.mongodb.net:27017', tagSet=TagSet{&#91;Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='US_EAST_1'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=10, topologyVersion=TopologyVersion{processId=61e5b12ff56b6bdfb1dc18fa, counter=3}, lastWriteDate=Mon Jan 17 14:51:12 MST 2022, lastUpdateTimeNanos=330476231174200}\n2022-01-17 14:51:12.621  INFO 23840 --- &#91;ngodb.net:27017] org.mongodb.driver.cluster               : Monitor thread successfully connected to server with description ServerDescription{address=bullyrooks-shard-00-01.4zqpz.mongodb.net:27017, type=REPLICA_SET_PRIMARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=9, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=279366100, setName='atlas-x20br4-shard-0', canonicalAddress=bullyrooks-shard-00-01.4zqpz.mongodb.net:27017, hosts=&#91;bullyrooks-shard-00-02.4zqpz.mongodb.net:27017, bullyrooks-shard-00-01.4zqpz.mongodb.net:27017, bullyrooks-shard-00-00.4zqpz.mongodb.net:27017], passives=&#91;], arbiters=&#91;], primary='bullyrooks-shard-00-01.4zqpz.mongodb.net:27017', tagSet=TagSet{&#91;Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='US_EAST_1'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=7fffffff00000000000000cc, setVersion=10, topologyVersion=TopologyVersion{processId=61dc74fe739b2f0c61413767, counter=13}, lastWriteDate=Mon Jan 17 14:51:12 MST 2022, lastUpdateTimeNanos=330476231480400}\n2022-01-17 14:51:12.621  INFO 23840 --- &#91;ngodb.net:27017] org.mongodb.driver.cluster               : Monitor thread successfully connected to server with description ServerDescription{address=bullyrooks-shard-00-00.4zqpz.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=9, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=278135600, setName='atlas-x20br4-shard-0', canonicalAddress=bullyrooks-shard-00-00.4zqpz.mongodb.net:27017, hosts=&#91;bullyrooks-shard-00-02.4zqpz.mongodb.net:27017, bullyrooks-shard-00-01.4zqpz.mongodb.net:27017, bullyrooks-shard-00-00.4zqpz.mongodb.net:27017], passives=&#91;], arbiters=&#91;], primary='bullyrooks-shard-00-01.4zqpz.mongodb.net:27017', tagSet=TagSet{&#91;Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='US_EAST_1'}, Tag{name='workloadType', value='OPERATIONAL'}]}, electionId=null, setVersion=10, topologyVersion=TopologyVersion{processId=61dc74e45b583b963580aabc, counter=14}, lastWriteDate=Mon Jan 17 14:51:12 MST 2022, lastUpdateTimeNanos=330476230523800}\n2022-01-17 14:51:12.624  INFO 23840 --- &#91;ngodb.net:27017] org.mongodb.driver.cluster               : Setting max election id to 7fffffff00000000000000cc from replica set primary bullyrooks-shard-00-01.4zqpz.mongodb.net:27017\n2022-01-17 14:51:12.625  INFO 23840 --- &#91;ngodb.net:27017] org.mongodb.driver.cluster               : Setting max set version to 10 from replica set primary bullyrooks-shard-00-01.4zqpz.mongodb.net:27017\n2022-01-17 14:51:12.625  INFO 23840 --- &#91;ngodb.net:27017] org.mongodb.driver.cluster               : Discovered replica set primary bullyrooks-shard-00-01.4zqpz.mongodb.net:27017<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Test and Verification<\/h2>\n\n\n\n<p>Now head over to postman and hit the service endpoint.  Just manual testing for now.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"869\" height=\"519\" src=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-41.png?resize=869%2C519&#038;ssl=1\" alt=\"\" class=\"wp-image-1226\" srcset=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-41.png?w=869&amp;ssl=1 869w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-41.png?resize=300%2C179&amp;ssl=1 300w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-41.png?resize=768%2C459&amp;ssl=1 768w\" sizes=\"auto, (max-width: 869px) 100vw, 869px\" data-recalc-dims=\"1\" \/><\/figure>\n\n\n\n<p>You can also log into mongo and see the record that was created<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"616\" height=\"153\" src=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-42.png?resize=616%2C153&#038;ssl=1\" alt=\"\" class=\"wp-image-1227\" srcset=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-42.png?w=616&amp;ssl=1 616w, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-42.png?resize=300%2C75&amp;ssl=1 300w\" sizes=\"auto, (max-width: 616px) 100vw, 616px\" data-recalc-dims=\"1\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Save to Git<\/h2>\n\n\n\n<p>We&#8217;re in a good spot. Save to git and push to remote<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ git add .\nwarning: LF will be replaced by CRLF in pom.xml.\nThe file will have its original line endings in your working directory\n\n$ git commit -m \"message endpoint\"\n&#91;database f6b7f59] message endpoint\n 12 files changed, 175 insertions(+)\n create mode 100644 src\/main\/java\/com\/bullyrooks\/cloud_application\/controller\/MessageController.java\n create mode 100644 src\/main\/java\/com\/bullyrooks\/cloud_application\/controller\/dto\/CreateMessageRequestDTO.java\n create mode 100644 src\/main\/java\/com\/bullyrooks\/cloud_application\/controller\/dto\/CreateMessageResponseDTO.java\n create mode 100644 src\/main\/java\/com\/bullyrooks\/cloud_application\/controller\/mapper\/CreateMessageRequestDTOMapper.java\n create mode 100644 src\/main\/java\/com\/bullyrooks\/cloud_application\/controller\/mapper\/CreateMessageResponseDTOMapper.java\n create mode 100644 src\/main\/java\/com\/bullyrooks\/cloud_application\/repository\/MessageRepository.java\n create mode 100644 src\/main\/java\/com\/bullyrooks\/cloud_application\/repository\/mapper\/MessageDocumentMapper.java\n create mode 100644 src\/main\/java\/com\/bullyrooks\/cloud_application\/service\/MessageService.java\n create mode 100644 src\/main\/java\/com\/bullyrooks\/cloud_application\/service\/model\/Message.java\n create mode 100644 src\/main\/resources\/application.yml\n\n$ git push\nEnumerating objects: 43, done.\nCounting objects: 100% (43\/43), done.\nDelta compression using up to 4 threads\nCompressing objects: 100% (24\/24), done.\nWriting objects: 100% (29\/29), 3.71 KiB | 950.00 KiB\/s, done.\nTotal 29 (delta 6), reused 0 (delta 0), pack-reused 0\nremote: Resolving deltas: 100% (6\/6), completed with 2 local objects.\nTo github.com-bullyrook:bullyrooks\/cloud_application.git\n   e24001a..f6b7f59  database -&gt; database\n<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"entry-summary\">\nThe first part of these courses was all about setting up an&hellip;\n<\/div>\n<div class=\"link-more\"><a href=\"https:\/\/bullyrooks.com\/index.php\/2022\/01\/23\/cloud-kube-pt2-setting-up-a-datastore\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &ldquo;Cloud Kube Pt2 | Setting Up a Datastore&rdquo;<\/span>&hellip;<\/a><\/div>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[41],"tags":[5,156,47,155,157,57,42,43],"course":[154],"class_list":["post-1220","post","type-post","status-publish","format-standard","hentry","category-software-development","tag-docker","tag-hexagonal-architecture","tag-mapstruct","tag-mongodb","tag-ports-and-adapters","tag-rest","tag-spring","tag-spring-boot","course-kubernetes-application-hosted-in-the-cloud-pt-2","entry"],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":1356,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/02\/27\/kube-cloud-pt5-create-an-event-consumer\/","url_meta":{"origin":1220,"position":0},"title":"Kube Cloud Pt5 | Create an Event Consumer","author":"Bullyrook","date":"February 27, 2022","format":false,"excerpt":"Now that we've got messages being published to kafka, we are going to need to build our consumer that receives those events and stores them into the mongo database. Go ahead and create a new repository called message-repository according to the microservice startup course here. This is the pom.xml that\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-49.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-49.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-49.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":1229,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/01\/23\/kube-cloud-pt2-automated-testing-with-testcontainers\/","url_meta":{"origin":1220,"position":1},"title":"Kube Cloud Pt2 | Automated Testing with TestContainers","author":"Bullyrook","date":"January 23, 2022","format":false,"excerpt":"In the last section we implemented service endpoint that stored data in a mongodb backend. In this session we're going to build a component test to automatically verify that functionality. TestContainer Overview TestContainers allow us to mock external resources with a docker based implementation. This is similar to \"regular\" mocking\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1339,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/02\/27\/kube-cloud-pt5-create-an-event-publisher\/","url_meta":{"origin":1220,"position":2},"title":"Kube Cloud Pt5 | Create an Event Publisher","author":"Bullyrook","date":"February 27, 2022","format":false,"excerpt":"We're going to be updating cloud-application to remove the mongodb repository logic and replace it with an event publisher. Create a new branch from main git checkout -b migrate Update the pom.xml first, remove the mongodb dependencies <dependency> <groupId>org.springframework.boot<\/groupId> <artifactId>spring-boot-starter-data-mongodb<\/artifactId> <\/dependency> ... <dependency> <groupId>org.testcontainers<\/groupId> <artifactId>mongodb<\/artifactId> <version>1.16.3<\/version> <scope>test<\/scope> <\/dependency> and add\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-39.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-39.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-39.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":1333,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/02\/27\/kube-cloud-pt5-create-a-consumer-service\/","url_meta":{"origin":1220,"position":3},"title":"Kube Cloud Pt5 | Create a Consumer Service","author":"Bullyrook","date":"February 27, 2022","format":false,"excerpt":"In this course we're going to migrate the repository storage function out of cloud-application and migrate it into a new service called message-repository. Although this is a relatively minor change in behavior (in exchange for a significant effort), there are some real world benefits that this example will provide cloud-application\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/pg1.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/pg1.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/pg1.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":1230,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/01\/23\/kube-cloud-pt2-database-configuration-in-kubernetes\/","url_meta":{"origin":1220,"position":4},"title":"Kube Cloud Pt2 | Database Configuration in Kubernetes","author":"Bullyrook","date":"January 23, 2022","format":false,"excerpt":"We now have an application that will connect to our MongoDB locally, but we'll need to tell it how to connect when its deployed to Okteto. Create Kubernetes Configuration First, create a secret in okteto with the database details. Run this command on your terminal. The uri should look like\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-43.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-43.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/01\/image-43.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":1264,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/02\/13\/kube-cloud-pt3-health-indicators\/","url_meta":{"origin":1220,"position":5},"title":"Kube Cloud Pt3 | Health Indicators","author":"Bullyrook","date":"February 13, 2022","format":false,"excerpt":"Spring offers a way to tell if your services and their dependent resources are up and healthy. Kubernetes can leverage this functionality via their liveness and readiness probes to report if pods are available to service requests. In this session, we're going to enable and connect those health checks. Enable\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-4.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-4.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-4.png?resize=700%2C400&ssl=1 2x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/1220","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/comments?post=1220"}],"version-history":[{"count":8,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/1220\/revisions"}],"predecessor-version":[{"id":1240,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/1220\/revisions\/1240"}],"wp:attachment":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/media?parent=1220"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/categories?post=1220"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/tags?post=1220"},{"taxonomy":"course","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/course?post=1220"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}