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
Development
K8S design constraints
And more!

Alexandre Touret

November 01, 2021
Tweet

More Decks by Alexandre Touret

Other Decks in Programming

Transcript

  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 Few concerns to address Small business application? Controlled

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

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

    you need to deliver environments on demand (and really fast)?
  6. #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.
  7. #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
  8. #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
  9. #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 • …
  10. #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
  11. #K8SBeyondTheHype @touret_alex TOMCAT vs FAT JARS A story of a

    Production – Development teams trade-off
  12. #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
  13. #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
  14. #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(); } } [...] }
  15. #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’ }
  16. #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
  17. #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
  18. #K8SBeyondTheHype @touret_alex How to configure your cloud native app? ▪

    Environment variables ▪ Config Maps ▪ Secrets
  19. #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
  20. #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
  21. #K8SBeyondTheHype @touret_alex What about configuration files? • We can specify

    them as variables in config maps • We can also externalize them
  22. #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 }}
  23. #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.
  24. #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 }}
  25. #K8SBeyondTheHype @touret_alex File templates apiVersion: v1 kind: ConfigMap metadata: name:

    configuration labels: [...] data: application.properties: |- {{ tpl (.Files.Get "conf/application.properties") . | nindent 4}}
  26. #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
  27. #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 }}
  28. #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
  29. #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
  30. #K8SBeyondTheHype @touret_alex Distributed tracing You can identify and correlate your

    API calls on your microservices based architecture by implement Opentracing
  31. #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)
  32. #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
  33. #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
  34. #K8SBeyondTheHype @touret_alex Distributed tracing By using Spring Cloud GCP starter

    trace dependencies { compile group: 'org.springframework.cloud', name: 'spring-cloud-gcp-starter-trace’ }