Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[DEVOXX UK 2021] Kubernetes & Co, beyond the hype: 10 tips for designers who want to create cloud native apps

[DEVOXX UK 2021] Kubernetes & Co, beyond the hype: 10 tips for designers who want to create cloud native apps

Kubernetes and cloud technologies are nowadays the new standard to deploy different cloud native applications: api, batchs, microservices and ... monoliths!
These technologies help to solve many issues but with some complexity.
It could be difficult for developers and designers to identify the constraints of such architectures.

In this presentation, you will (re)discover ten tips and pieces of advice I applied and found useful in my last JAVA projects (Spring, JEE).

I will talk about:

Application ecosystem
Choice of technical solutions
K8S design constraints
And more!


Alexandre Touret

November 01, 2021

More Decks by Alexandre Touret

Other Decks in Programming


  1. #K8SBeyondTheHype @touret_alex Kubernetes & Co, beyond the hype: 10 tips

    for designers who want to create cloud native apps! Alexandre Touret @touret_alex blog.touret.info www.worldline.com
  2. #K8SBeyondTheHype @touret_alex Kubernetes & Co, beyond the hype: 10 tips

    for designers who want to create cloud native apps Alexandre Touret Architect / Developer #Java #API #CI #Cloud #Software_Craftsmanship
  3. #K8SBeyondTheHype @touret_alex SOME CONTEXT

  4. #K8SBeyondTheHype @touret_alex

  5. #K8SBeyondTheHype @touret_alex Used technologies

  6. #K8SBeyondTheHype @touret_alex DO YOU REALLY NEED IT?

  7. #K8SBeyondTheHype @touret_alex Few concerns to address Small business application? Controlled

    scope? Automatized deployments already implemented? Any compliancy constraints?
  8. #K8SBeyondTheHype @touret_alex What are the NFRs? Do you have constraining

    SLOs? (eg. >99% SLA availability) Does your system need to be dynamically scaled?
  9. #K8SBeyondTheHype @touret_alex Providing « on demand » platforms • Do

    you need to deliver environments on demand (and really fast)?
  10. #K8SBeyondTheHype @touret_alex Why I considered K8S as a target platform?

    • For a new app, we had these NFRs: • 99,95% availability SLA level • Need to deal with peak throughputs (e.g., dynamically scaling for the black Friday) • Need to provide “on-demand” platforms (e.g., DRS, sandboxes for our customers ) • We also chose this technology because we already had an available Openshift© shared platform and the associated tooling.
  11. #K8SBeyondTheHype @touret_alex DOCKER & CIE BASICS

  12. #K8SBeyondTheHype @touret_alex

  13. #K8SBeyondTheHype @touret_alex You will have to know

  14. #K8SBeyondTheHype @touret_alex

  15. #K8SBeyondTheHype @touret_alex On my side… Support Training sessions Getting started

    GITLABCI templates
  16. #K8SBeyondTheHype @touret_alex ORGANISATION

  17. #K8SBeyondTheHype @touret_alex “Any organization that designs a system (defined broadly)

    will produce a design whose structure is a copy of the organization's communication structure.” M. Conway
  18. #K8SBeyondTheHype @touret_alex Responsability Assignment Matrix (RACI) What’s the associated RACI

    ? Is your organisation compatible?
  19. #K8SBeyondTheHype @touret_alex THE STATELESS APPS AND THE OTHERS…

  20. #K8SBeyondTheHype @touret_alex Codebase One codebase tracked in revision control, many

    deploys Dependencies Explicitly declare and isolate dependencies Config Store config in the environment Backing Services Treat backing services as attached resources Build, release, run Strictly separate build and run stages Concurrency Scale out via the process model Processes Execute the app as one or more stateless processes Port Binding Export services via port binding Disposability Maximize robustness with fast startup and graceful shutdown Dev/prod parity Keep development, staging, and production as similar as possible Logs Treat logs as event streams Admin processes Run admin/management tasks as one-off processes
  21. #K8SBeyondTheHype @touret_alex For an API Processes Config Concurrency Disposability Port

    binding Dev prod parity
  22. #K8SBeyondTheHype @touret_alex (FAST) APPLICATION STARTUP

  23. #K8SBeyondTheHype @touret_alex

  24. #K8SBeyondTheHype @touret_alex How to do that with Spring boot? •

    Checking your requirements first • Activating Lazy initialization spring.main.lazy-initialization=true • Disabling autoconfiguration and use @Import annotation • Activating Graceful shutdown handling server.shutdown=graceful • …

  26. #K8SBeyondTheHype @touret_alex

  27. #K8SBeyondTheHype @touret_alex Items to check • Fast startup • Shutdown

    handling • Ability to be integrated into Docker and K8S • Observability • Memory and CPU consumption • Dependency and patch management
  28. #K8SBeyondTheHype @touret_alex TOMCAT vs FAT JARS A story of a

    Production – Development teams trade-off
  29. #K8SBeyondTheHype @touret_alex OBSERVABILITY

  30. #K8SBeyondTheHype @touret_alex Address this point from design phase • Don’t

    wait for the production deployment • Expose your system status through endpoints • Be careful to the used FRAMEWORKS
  31. #K8SBeyondTheHype @touret_alex Liveness & readiness probes livenessProbe: failureThreshold: 3 httpGet:

    path: /actuator/health/liveness port: http scheme: HTTP initialDelaySeconds: 30 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 readinessProbe: failureThreshold: 3 httpGet: path: /actuator/health/readiness port: http scheme: HTTP initialDelaySeconds: 30 periodSeconds: 30 successThreshold: 1 timeoutSeconds: 1
  32. #K8SBeyondTheHype @touret_alex Spring Actuator dependencies { implementation 'org.springframework.boot:spring-boot-starter- actuator' }

  33. #K8SBeyondTheHype @touret_alex Spring Actuator management.health.probes.enabled=true management.endpoints.enabled-by-default=true management.health.livenessstate.enabled=true management.health.readinessstate.enabled=true management.endpoint.health.show-details=always management.endpoint.health.probes.enabled=true

    management.endpoint.health.enabled=true LivenessStateHealthIndicator & ReadinessStateHealthIndicator
  34. #K8SBeyondTheHype @touret_alex Overriding a Heath Indicator @Component public class MongoDBActuatorHealthIndicator

    implements HealthIndicator { [...] @Override public Health health() { // ping database } @Override public Health getHealth(boolean includeDetails) { if (!includeDetails) { return health(); } else { var statuses = mongoDBHealthService.findStatusForAllConfigurations(); return Health.status(checkStatus(statuses)).withDetails(statuses).build(); } } [...] }
  35. #K8SBeyondTheHype @touret_alex Monitoring • Micrometer • Prometheus • Grafana

  36. #K8SBeyondTheHype @touret_alex Micrometer • Help you exporting metrics (e.g., the

    TTR of an API using the @Timed annotation) • These metrics could be aggretated into Prometheus dependencies { implementation 'io.micrometer:micrometer-registry-prometheus’ }
  37. #K8SBeyondTheHype @touret_alex management: endpoints: enabled-by-default: true web: exposure: include: '*'

    jmx: exposure: include: '*' endpoint: health: show-details: always enabled: true probes: enabled: true shutdown: enabled: true prometheus: enabled: true metrics: enabled: true health: livenessstate: enabled: true readinessstate: enabled: true datasource: enabled: true metrics: web: client: request: autotime: enabled: true Actuator configuration Metrics configuration
  38. #K8SBeyondTheHype @touret_alex CI/CD

  39. #K8SBeyondTheHype @touret_alex Two kind of pipelines • Platform provisioning •

    Application build & deploy
  40. #K8SBeyondTheHype @touret_alex Platform provisionning terraform apply

  41. #K8SBeyondTheHype @touret_alex Application build & deploy Build • Java application

    • Docker image • Helm chart Tests • Unit & integration tests • Smoke tests of the new docker image Deployment • Continuous deployment of your develop branch • Release deployment
  42. #K8SBeyondTheHype @touret_alex Example Spring Boot, Tomcat, JDK Migration Tested locally

    → Dev → Staging ⇒ In one day
  43. #K8SBeyondTheHype @touret_alex CONFIGURATION

  44. #K8SBeyondTheHype @touret_alex How to configure your cloud native app? ▪

    Environment variables ▪ Config Maps ▪ Secrets
  45. #K8SBeyondTheHype @touret_alex Environment variables spec: containers: - env: - name:

    JAVA_OPTS value: >- -XX:+UseContainerSupport -XX:MaxRAMPercentage=70.0 -Dfile.encoding=UTF-8 - Djava.security.egd=file:/dev/./urandom
  46. #K8SBeyondTheHype @touret_alex Config map apiVersion: v1 kind: ConfigMap metadata: creationTimestamp:

    2021-03-11T18:38:34Z name: my-config-map [...] data: JAVA_OPTS: >- -XX:+UseContainerSupport -XX:MaxRAMPercentage=70.0 -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom
  47. #K8SBeyondTheHype @touret_alex What about configuration files? • We can specify

    them as variables in config maps • We can also externalize them
  48. #K8SBeyondTheHype @touret_alex Files in Config map volumeMounts: - mountPath: /config

    name: configuration-volume readOnly: true [...] volumes: - configMap: defaultMode: 420 name: configuration name: configuration-volume apiVersion: v1 kind: ConfigMap [...] data: my.conf: {{- (.Files.Glob "conf/*").AsConfig | nindent 2 }}
  49. #K8SBeyondTheHype @touret_alex Limitations Error: UPGRADE FAILED: ConfigMap "my-service" is invalid:

    data: Too long: must have at most 1048576 characters https://kubernetes.io/docs/concepts/configuration/configmap/ A ConfigMap is not designed to hold large chunks of data. The data stored in a ConfigMap cannot exceed 1 MiB. If you need to store settings that are larger than this limit, you may want to consider mounting a volume or use a separate database or file service.
  50. #K8SBeyondTheHype @touret_alex How to externalise values? apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler

    metadata: labels: [...] spec: maxReplicas: {{ .Values.myapp.maxReplicaCount }} minReplicas: {{ .Values.myapp.minReplicaCount }} [...] targetCPUUtilizationPercentage: {{ .Values.myapp.replicationThreesold }}
  51. #K8SBeyondTheHype @touret_alex Values.yml myapp: minReplicaCount: "2" maxReplicaCount: "6" replicationThreesold: 80

  52. #K8SBeyondTheHype @touret_alex File templates apiVersion: v1 kind: ConfigMap metadata: name:

    configuration labels: [...] data: application.properties: |- {{ tpl (.Files.Get "conf/application.properties") . | nindent 4}}
  53. #K8SBeyondTheHype @touret_alex Templates application.properties logging.level.org.hibernate.stat={{ .Values.configmap.application.org_hi bernate_stat }} logging.level.org.springframework.se curity={{

    .Values.configmap.application.org_sp ringframework_security }} values.yml configmap: application: org_hibernate_stat: ERROR org_springframework_security: ERROR
  54. #K8SBeyondTheHype @touret_alex Binary files apiVersion: v1 # Definition of secrets

    kind: Secret [...] type: Opaque # Inclusion of binary configuration files data: my_keystore.jks: {{ .Files.Get "secrets/my_keystore.jks" | b64enc }}
  55. #K8SBeyondTheHype @touret_alex EFFICIENT LOGGING

  56. #K8SBeyondTheHype @touret_alex Log management In the console: kubectl logs --tail

    Logs aggregator (e.g., ELK, Google Logs Explorer)
  57. #K8SBeyondTheHype @touret_alex Docker containers output stream stdout & stderr It’s

    useless to setup a file output stream
  58. #K8SBeyondTheHype @touret_alex Best pratices Indicate in your LOGS: • Container

    information (image name, container ID,…) • Kubernetes related information (POD @IP, POD ID, namespace,...) Log4j Docker Support – Log4j Kubernetes Support
  59. #K8SBeyondTheHype @touret_alex To go further • You can identify the

    related informations of the APIs calls: Caller ID, Correlation ID, request data,… zalando/logbook: An extensible Java library for HTTP request and response logging
  60. #K8SBeyondTheHype @touret_alex Distributed tracing You can identify and correlate your

    API calls on your microservices based architecture by implement Opentracing
  61. #K8SBeyondTheHype @touret_alex Configuring Opentracing dependencies { implementation 'io.opentracing.contrib:opentracing-spring-jaeger- cloud-starter:3.3.1’ }

    application.properties opentracing: jaeger: udp-sender: host: localhost port: 6831 enabled: true
  62. #K8SBeyondTheHype @touret_alex https://blog.worldline.tech/2021/09/22/enabling_distributed_tracing_in_spring_apps.html

  63. #K8SBeyondTheHype @touret_alex On Google Cloud Platform You have by default:

    • A log explorer (Google Logs Explorer ~ ELK) • An error reporter(~ ELK specific dashboard) • A distributed trace analyser (~ Opentracing/Jaeger)
  64. #K8SBeyondTheHype @touret_alex Logging Use Spring Cloud GCP starter dependencies {

    implementation("com.google.cloud:spring-cloud-gcp-starter- logging") } Configure using Logback as logging framework Set the GOOGLE_CLOUD_PROJECT & GOOGLE_APPLICATION_CREDENTIALS environment variables in your HELM charts
  65. #K8SBeyondTheHype @touret_alex Logging

  66. #K8SBeyondTheHype @touret_alex Error Reporter By default, it aggregates all your

    platform’s errors You can also add your business errors (HTTP 500) There are Logback appenders and JUL handlers provided by Google
  67. #K8SBeyondTheHype @touret_alex Distributed tracing By using Spring Cloud GCP starter

    trace dependencies { compile group: 'org.springframework.cloud', name: 'spring-cloud-gcp-starter-trace’ }
  68. #K8SBeyondTheHype @touret_alex