{"id":18013123,"url":"https://github.com/tajpouria/docker-and-kubernetes-cheat-sheet","last_synced_at":"2026-01-21T11:33:53.941Z","repository":{"id":114980141,"uuid":"215405891","full_name":"tajpouria/docker-and-kubernetes-cheat-sheet","owner":"tajpouria","description":"Docker \u0026 K8s Cheat Sheet","archived":false,"fork":false,"pushed_at":"2022-11-24T11:20:13.000Z","size":18830,"stargazers_count":19,"open_issues_count":0,"forks_count":7,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-26T07:46:40.935Z","etag":null,"topics":["docker","docker-cli","docker-compose","istio","kubernetes","linux","vault"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tajpouria.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-10-15T22:12:20.000Z","updated_at":"2025-06-08T10:24:31.000Z","dependencies_parsed_at":null,"dependency_job_id":"10693084-9a4d-427e-a8ee-af220443d9c6","html_url":"https://github.com/tajpouria/docker-and-kubernetes-cheat-sheet","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tajpouria/docker-and-kubernetes-cheat-sheet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tajpouria%2Fdocker-and-kubernetes-cheat-sheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tajpouria%2Fdocker-and-kubernetes-cheat-sheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tajpouria%2Fdocker-and-kubernetes-cheat-sheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tajpouria%2Fdocker-and-kubernetes-cheat-sheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tajpouria","download_url":"https://codeload.github.com/tajpouria/docker-and-kubernetes-cheat-sheet/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tajpouria%2Fdocker-and-kubernetes-cheat-sheet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28632771,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-21T04:47:28.174Z","status":"ssl_error","status_checked_at":"2026-01-21T04:47:22.943Z","response_time":86,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","docker-cli","docker-compose","istio","kubernetes","linux","vault"],"created_at":"2024-10-30T03:19:54.003Z","updated_at":"2026-01-21T11:33:53.932Z","avatar_url":"https://github.com/tajpouria.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Docker\n\n## Why use docker\n\nBriefly, because it makes it really easy to install and run software without worrying about setup or dependencies.\n\n## What is docker\n\nDocker is a platform or ecosystem contains a bunch of tools(e.g. Docker Client, Docker Server, Docker Machine, Docker Images, Docker Hub, Docker Compose) that comes together to creating and running containers.\n\n### What's the container\n\nBriefly, when we run `docker run sth` this is what happening : Docker Cli reach to something named Docker Hub and download the **Image** contains the a bunch of configuration and dependencies to install and running a very specific program _the images file will store on hard drive_ and on some point of time you can use this image to create a container, so the container is an instance of image a we can look at as an running program, in other word a container is a program with it's own set of hardware resources that have it's own little space of memory it's own little space of networking and it's own little space of hard drive as well.\n\n## Docker for windows/mac\n\nContains:\n\n- Docker Client (Docker CLI)\n  Tool that we are going to issue commands to\n- Docker Server (Docker Daemon)\n  Tool that is responsible for creating images, running containers and etc\n\n## Installing Docker Engine - Community and Docker-Compose\n\nIf you wish, Docker can also be installed on many different types of Linux distributions. This note covers how to install with Ubuntu, but the Docker docs have instructions for CentOS, Debian and Fedora as well.\n\nInstallation\n\n_Note_: These steps were successfully completed with Ubuntu Desktop 18 LTS\n\n_Note_: Linux mint 19.2 gotcha on adding repo:\nMalformed input, repository not added.I fixed by just removing the [arch=amd64] from the source.\n\n\u003e sudo add-apt-repository \"deb https://download.docker.com/linux/ubuntu bionic stable\"\n\nThe docs for Ubuntu installation suggest setting up a Docker repository to install and update from.\n\nThis is where you should start:\n\nhttps://docs.docker.com/install/linux/docker-ce/ubuntu/#set-up-the-repository\n\nAfter completing the installation steps, test out Docker:\n\nsudo docker run hello-world\n\nThis should download and run the test container printing \"hello world\" to your console.\n\nInstalling Docker Compose\n\nUnlike the Mac and Windows Docker Desktop versions, we must manually install Docker Compose. See the instructions for the installation steps (Click on the tab for Linux)\n\nhttps://docs.docker.com/compose/install/#install-compose\n\nAfter completing, test your installation:\n\ndocker-compose -v\n\nThis should print the version and build numbers to your console.\n\nRun without Sudo\n\nFollow these instructions to run Docker commands without sudo:\n\nhttps://docs.docker.com/install/linux/linux-postinstall/#manage-docker-as-a-non-root-user\n\nThe docker group will likely already be created, but you still need to add your user to this group.\n\nStart on Boot\n\nFollow these instructions so that Docker and its services start automatically on boot:\n\nhttps://docs.docker.com/install/linux/linux-postinstall/#configure-docker-to-start-on-boot\n\nYou may need to restart your system before starting the course material.\n\n## Using the docker client\n\n\u003e docker run hello-world\n\nWhat just happened when we run this command:\n\n1. we run the command `docker run hello-world` on docker cli (that mean we gonna run a container with an image named hello-world)\n2. docker cli issue to docker daemon (server)\n3. docker daemon check to see if we have a local copy of hello-world image on some thing called **Image Cache**\n4. if hello-world image does not exist on image cache docker daemon will reach out to some free service named **Docker Hub** (the repository of free images that we can download an install)\n5. docker daemon will download hello-world image and store it on image cache _then we can install and rerun it later without reaching to docker hub_\n6. then docker server took that single file, load it on the memory to create a container of it run the program inside of it\n7. then hello-world program will run in the container and it's whole purpose is to print some text on the terminal\n\n## Manipulating docker cli\n\n### Create and running a container from an image\n\n\u003e docker run hello-world\n\nrunning and starting on the background\n\n\u003e docker run -d busybox\n\nOverriding default commands:\n\n\u003e docker run busybox ls\n\nexecuting specified command in container\n\noutput:\n\n```shell\n.\n..\n.dockerenv\nbin\ndev\netc\nhome\nproc\nroot\nsys\ntmp\nusr\nvar\n```\n\n### List all running containers\n\n\u003e docker ps\n\nList all the containers the have been created:\n\n\u003e docker ps --all\n\n### Container life cycle\n\ndocker run = docker create + docker start\n\ncreating a container:\n\n\u003e docker create busy-box ls -a\n\ncreate a container and return it's id:\n\n```shell\nbd9fb4cd2ae040fb9413be7368d7a693f8e83780f6dcde92a65d6f8570fc045089\n```\n\n\u003e docker ps --all\n\noutput\n\n```shell\nCONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES\nbd9fb4cd2ae0        busybox             \"ls -a\"             12 seconds ago      Created                                 exciting_hodgkin\n\n```\n\ncontainer is in **Created** STATUS\n\nstart the container with a watcher attached to it's output to print out on the terminal\n\n\u003e docker start -a bd9fb4cd2ae040fb9413be7368d7a693f8e83780f6dcde92a65d6f8570fc045089\n\noutput:\n\n```shell\n.\n..\n.dockerenv\nbin\ndev\netc\nhome\nproc\nroot\nsys\ntmp\nusr\nvar\n```\n\n\u003e docker ps --all\n\noutput\n\n```shell\nCONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES\nbd9fb4cd2ae0        busybox             \"ls -a\"             3 minutes ago       Exited (0) 7 seconds ago                       exciting_hodgkin\n\n```\n\ncontainer is in **Exited** STATUS\n\n### Removing containers\n\nRemove all stopped containers, all dangling images, and all unused networks:\n\n\u003e docker system prune\n\nYou’ll be prompted to continue, use the `-f` or `--force` flag to bypass the prompt.\n\nRemove by CONTAINER_ID(s):\n\n\u003e docker container rm CONTAINER_ID_1 CONTAINER_ID_2\n\nRemove all stopped containers:\n\n\u003e docker container prune\n\n### Removing images\n\nList of images\n\n\u003e docker images --all\n\nRemove by IMAGE_ID(s):\n\n\u003e docker image rm IMAGE_ID\n\n### Retrieving log output\n\n\u003e docker logs CONTAINER_ID\n\n### Stop / kill container\n\n\u003e docker stop CONTAINER_ID\n\n\u003e docker kill CONTAINER_ID\n\nRecommended docker stop to stop a process it will automatically run docker kill command if container not stop after 10 sec\n\n### Executing command in a running container\n\n\u003e docker run redis\n\nThis command will create container and then start redis-server into it\n\n\u003e docker ps\n\noutput:\n\n```shell\nCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES\nc7c021ce2637        redis               \"docker-entrypoint.s…\"   6 minutes ago       Up 6 minutes        6379/tcp            stupefied_lamport\n```\n\n\u003e docker exec -it c7c021ce2637 redis-cli\n\nThe `-it` flag makes the container to receive input; without specifying this flag the process will start but don't let us to issue the inputs\n\n### The it flag purpose\n\nEvery processes (in docker container) that running on linux environment have three communication channel attach to it:\nthis channels is using to communicate information either into the process or out of the process:\n\n- STDIN: Comminute information into the process\n- STDOUT: Convey information that coming out of the process\n- STDERR: Covey information out of the process that kinds of like errors\n\nThe `-it` flag is shorten of two separate`-i` and `-t` flag:\n\n- -i flags mean when we run this command we are going to attach or terminal to the STDIN channel of running process\n- -t briefly make the out come texts show pretty(indent and etc)\n\n## Getting a command prompt in a container\n\n\u003e docker exec -it 4aec7087de55 sh\n\n`sh` is some kind of command shell program like bash, zsh or ... that allow us to issue command on terminal. Traditionally a lots of containers that we are going to working with contains sh program\n\n### Starting with a shell\n\n\u003e docker run -it busybox sh\n\n## Building custom images through docker daemon\n\nHere is the steps we gonna go through:\n\n1.  setup Dockerfile: a plain text file that define how our **container** should behave in other word whats programs it contains and how it's behave when first startup\n2.  pass the Dockerfile to dockerCli and dockerCli will pass to dockerDaemon\n3.  dockerDaemon will look up to docker file and will create a **usable image** of it\n\n### Building a Dockerfile\n\nflow of creating a Dockerfile:\n\n1. specify a base image\n2. run some command to install additional programs\n3. specify a command to run on container startup\n\n./Dockerfile\n\n```Dockerfile\n# specify the base image\nFROM alpine\n\n# download and install additional programs\nRUN apk add --update redis\n\n# specify a command to run on container startup\nCMD [\"redis-server\"]\n```\n\n### .dockerignore https://codefresh.io/docker-tutorial/not-ignore-dockerignore-2/\n\nHelps to define the build context:\n\n./.dockerignore\n\n```\n# ignore .git and .cache folders\n.git\n.cache\n\n# ignore all *.class files in all folders, including build root\n**/*.class\n\n# ignore all markdown files (md) beside all README*.md other than README-secret.md\n*.md\n!README*.md\nREADME-secret.md\n```\n\n\u003e docker build .\n\n\u003e docker run ImageID\n\nWhat's happening after running `docker build .` _dot( . ) is the build context of the container_\n\n1. dockerCli will pass DockerFile to dockerDeamon\n2. dockerDaemon look at the localCash to find the `base image` (in our case alpine) then either download it or using existing one\n3. dockerDaemon will initialized the base image\n4. when dockerDaemon is about to running the `RUN` command it will create a `intermediate container` from the base image (in our case alpine)\n5. dockerDaemon will run the specified command into that intermediate container (in our case `apk add --update redis`) and take it file snapshot (the actual image or images that downloaded)\n6. dockerDaemon removing the intermediate container\n7. dockerDaemon will take the file snapshot and the starting command then make a temporary image of it\n\n### tagging an Image\n\n\u003e docker build -t tajpouria/redis:latest .\n\n\u003e docker run tajpouria/redis\n\n### Manual image generating with docker commit\n\n\u003e docker run -it alpine sh\n\u003e \\#apk add --update redis\n\n\u003e docker commit -c '[\"redis-server\"]' CONTAINER_ID\n\n## Building a simple server with docker\n\n./Dockerfile\n\n```Dockerfile\n# install node baseImage with alpine tag tie to it\nFROM node:alpine\n\n# specifying a working directory for application\nWORKDIR /usr/simpleServer\n\n# copy file(s) from [ path relative to building context ] to [ path into container relative to WORKDIR ]\nCOPY ./package.json ./\n\nRUN npm i\n\n# separating COPY command because we don't want to reinstall all the dependencies after changing to source files\nCOPY ./ ./\n\nCMD [\"npm\", \"start\"]\n```\n\n### Container port mapping\n\n\u003e docker run -p 4000:8080 IMAGE_ID/NAME\n\nThat's mean anytime that a request comes to port 4000 of `my machine` redirect it to port 8080 `inside the container`\n\n## Docker compose with multiple local containers\n\n### Docker compose\n\ndocker-compose is a separate cli installed with docker, used to start up multiple docker containers at the same time, automates some of the long-winded arguments we were passing to `docker run`\n\n### docker-compose.yml\n\n`docker-compose.yml` contains all the options we'd normally pass to docker-cli\n\nwith this knowledge as an instance here is the containers we gonna create:\n\n- redis-server: make it using redis image\n\n- visits-server: make it using Dockerfile then connect it's port to local machine\n\n./docker-compose.yml\n\n```yml\n# the version of docker-compose\nversion: \"3\"\n# type of containers\nservices:\n  redis-server:\n    image: \"redis\" # use this image to build this container\n  visits-server:\n    build: . # build this container using Dockerfile in this directory\n    ports:\n      - \"4000:8080\" # map [local machine port]:[container port]\n```\n\nthen we can us it connect our server to redis-container\n\n./index.ts\n\n```typescript\nconst redisClient = redis.createClient({\n  host: \"redis-server\", // docker parse as an url\n  port: 6379,\n});\n```\n\n./Dockerfile\n\n```Dockerfile\nFROM node:alpine\n\nWORKDIR /usr/visits-server\n\nCOPY ./package.json .\n\nRUN npm i\n\nCOPY . .\n\nCMD [\"npm\", \"start\"]\n\n```\n\n### docker-compose commands\n\n- docker run myImage:\n\n\u003e docker-compose up\n\n\u003e docker-compose up -d\n\n- docker build . \u0026 docker run myImage **use when make change in images**\n\n\u003e docker-compose up --build\n\n- docker stop CONTAINER_ID\n\n\u003e docker-compose down\n\n- docker ps\n  \u003e docker-compose ps\n\n### Container maintenance with compose\n\n### Restart policies\n\n- **\"no\"**`( default )`: never attempts to restart this . container if it stops or crashes\n\n- **always**: if this container stops `always` attempt to restart it\n\n- **on-failure**: only restart the container stops with an `error code`\n\n- **unless-stopped**: always restart unless we forcibly stop it _on cli_\n\n_just \"no\" have quote in yml files no will interpreted as false_\n\n./docker-compose.yml\n\n```yml\nversion: \"3\"\nservices:\n  visits-server:\n    restart: always\n```\n\n## A productions grade workflow\n\n[Following description project repository](https://github.com/tajpouria/Docker-Travis-Test)\n\nThe process of development, testing and deployment and eventually on some point of time doing some additional development, additional testing and redeploy the application\n\n### A development image\n\n./Dockerfile.dev\n\n```Dockerfile\nFROM node:alpine\n\nWORKDIR /usr/react-app\n\nCOPY ./package.json .\n\nRUN npm i\n\nCOPY . .\n\nCMD [\"npm\", \"run\", \"start\"]\n```\n\nbuild Dockerfile with custom name using `-f` flag:\n\n\u003e docker build -f Dockerfile .\n\n### Docker volumes\n\nWith a dockerVolume we essentially setup some placeholder of sorts inside our container and instead of copy files we reference that file to the actual container in other word we mapping a folder inside a container to a folder outside a container\n\nusing `-v` flag you can either bookmark a file or map it, for example in following command:\n\n_in following make sure the paths are absolute_\n\n\u003e docker run -p 3000:8080 -v /usr/react-app/node_modules/ -v \\$(pwd):/usr/react-app/ IMAGE_ID\n\n- node_modules `book marked` means do not map this file with an external file\n- and other files in **present working directory(pwd)** are mapped(referenced) to external files and folders\n\n### Shorthand with docker-compose\n\n./docker-compose.yml\n\n_the paths has to absolute_\n\n```yml\nversion: \"3\"\nservices:\n  react-app:\n    build: # specify costume named docker file to build\n      context: .\n      dockerfile: Dockerfile.dev # SUPER IMPORTAND docker file paht relative context\n    ports:\n      - \"3000:8080\"\n    volumes:\n      - \"/usr/rect-app/node_modules\" # bookmark\n      - \".:/usr/react-app\" # reference\n```\n\n### Live updating tests\n\nHere is two diffrend approach to run our tests\n\n- attach the running container:\n\n\u003e docker exec -it IMAGE_ID npm run test\n\n- docker-compose\n\n```yml\nversion: \"3\"\nservices:\n  # rect-app ...\n  tests:\n    build:\n      context: .\n      dockerfile: Dockerfile.dev\n    volumes:\n      - \"usr/react-app/node_modules\"\n      - \".:/usr/rect-app\"\n    command: [\"npm\", \"run\", \"test\"] # overriding startup command\n```\n\nis it any way to interact with test service:\n\nafter running sh on container that is network between react-app and tests:\n\n- \u003e \\# ps\n\noutput:\n\n```shell\nPID   USER     TIME  COMMAND\n    1 root      0:00 npm\n   17 root      0:00 node /usr/react-app/node_modules/.bin/react-scripts start\n   24 root      0:05 node /usr/react-app/node_modules/react-scripts/scripts/start.js\n  130 root      0:00 sh\n  136 root      0:00 ps\n\n```\n\nas you see the primary process that is going on in this container with PID 1, but the problem is after running `docker attach CONTAINER_ID` it will automatically attach to primary process but for interacting to tests process we need to connect to start.js with PID of 24\n\n### A production image\n\n### Multi-step docker process\n\nUsing this feature when we're gonna have multi blocks of configuration for instance in our application we're gonna have two block of configuration:\n\n1. build phase purpose:\n\n- using node:alpine\n- copy package.json\n- install dependencies\n- run npm run build\n\n2. run phase purpose:\n\n- use nginx\n- copy over the results of npm run build **(essentially all the we copy the build folder and the other stuff like(node:alpine, node_modules and etc) drop from the result container)**\n- start nginx\n\n./Dockerfile\n\n```Dockerfile\n# tag the stage as builder\nFROM node:alpine as builder\nWORKDIR /usr/react-app\nCOPY ./package.json .\nRUN npm i\nCOPY . .\nRUN npm run build\n# the build folder we create at usr/react-app\n\nFROM nginx\n# putting EXPOSE 80 like this do nothing automatically in most environment (e.g. development environment) and is some kind of communication of sorts between developers to understand it container needs to some port mapped to port 80 but aws elastic beans talks will look for this EXPOSE and mapped it automatically\nEXPOSE 80\n# copy build folder from builder stage into user/share/nginx/html and nginx will automatically serve it when startup\nCOPY --from=builder /usr/react-app/build usr/share/nginx/html\n# nginx will automatically set start command\n```\n\n\u003e docker build .\n\n_nginx default port is `80`_\n\n\u003e docker run -p 8080:80 CONTAINER_ID\n\n## Continues integration\n\n### Travis yml file configuration\n\nHere is the steps we're gonna put in this file\n\n- tell the travis we need a copy of docker running to build the project and running the tests suits\n- build the project using the Dockerfile.dev (cuz the our Dockerfile not contains dependencies to run tests)\n- tell the travis how to run the test suits\n- tell the travis how to deploy our project over to aws\n\n.travis.yml\n\n```yml\n# any time we use the docker we need to have super user permission\nsudo: required\n\n# we need a copy of docker\nservices:\n  - docker\n\n# gonna have a series of different command that get executed before another process (in our case before the tests run)\nbefore_install:\n  - docker build -t tajpouria/docker-travis-test -f dockerfile.dev .\n# commands to run our tests suits\n# travis CI is gonna watch out the output of each of this command: if one of the scripts return exit with status code except 0 the travis gonna assume that the test suit is actually failed and our code is essentially broken\n# *** default behavior of npm run test is to hangout with output and not exit automatically so the travis will never gonna receive the exit status code we can exit the test after running it by specifying -- --watchAll=false flag\nscript:\n  - docker run tajpouria/docker-travis-test npm run test -- --watchAll=false\n\ndeploy:\n  provider: elasticbeanstalk\n  region: \"us-east-1\"\n  app: \"react-docker\"\n  env: \"Docker-env\"\n  bucket_name: \"elasticbeanstalk-us-east-1-746123612876210\"\n  bucket_path: \"react-docker\"\n  on:\n    branch: master\n  access_key_id: $AWS_ACCESS_KEY\n  secret_access_key:\n    secure: \"$AWS_SECURE_KEY\"\n```\n\n## A Multi Container Application\n\n[Following description project repository **/branch master**](https://github.com/tajpouria/Docker-Multiple-Container-Test/tree/master)\n\n### docker-compose environment variables\n\nthis is gonna set up a variable inside the container at **run-time** of the container:\n\n- `variableName=value`\n- `variableName` the value is taken from machine\n\ndocker-compose.yml\n\n```yml\nversion: \"3\"\nservices:\n  postgres:\n  restart: \"always\"\n  build:\n    dockerfile: Dockerfile.dev\n    context: ./postgres\n  environment:\n    - \"FILLA_DB_USER=docker\"\n    - \"FILLA_DB_PASSWORD=postgres_password\"\n    - \"FILLA_DB_DATABASE=multi_docker\"\n  redis:\n    image: \"redis:latest\"\n  nginx:\n    restart: always\n    build:\n      dockerfile: dockerfile.dev\n      context: ./nginx\n    ports:\n      - \"3000:80\"\n  api:\n    build:\n      dockerfile: Dockerfile.dev\n      context: ./api # it will find Dockerfile.dev into this context\n    volumes:\n      - usr/app/node_modules\n      - ./api :usr/app # *** make sure to specify each volume to related folder\n    environment: # specify environment variables\n      - REDIS_HOST=redis\n      - REDIS_PORT=6379\n      - PGUSER=docker\n      - PGHOST=postgres\n      - PGDATABASE=multi_docker\n      - PGPASSWORD=postgres_password\n      - PGPORT=5432\n  client:\n    build:\n      dockerfile: Dockerfile.dev\n      context: ./client\n    volumes:\n      - usr/app/node_modules\n      - ./client:usr/app\n  worker:\n    build:\n      dockerfile: Dockerfile.dev\n      context: ./worker\n    volumes:\n      - usr/app/node_modules\n      - ./worker:usr/worker\n```\n\n### Postgres create init database\n\n./postgres/init/01-filladb.sh\n\n```shell\n#!/bin/bash\n\n# Immediately exits if any error occurs during the script\n# execution. If not set, an error could occur and the\n# script would continue its execution.\nset -o errexit\n\n\n# Creating an array that defines the environment variables\n# that must be set. This can be consumed later via arrray\n# variable expansion ${REQUIRED_ENV_VARS[@]}.\nreadonly REQUIRED_ENV_VARS=(\n  \"FILLA_DB_USER\"\n  \"FILLA_DB_PASSWORD\"\n  \"FILLA_DB_DATABASE\"\n  \"POSTGRES_USER\")\n\n\n# Main execution:\n# - verifies if all environment variables are set\n# - runs the SQL code to create user and database\nmain() {\n  check_env_vars_set\n  init_user_and_db\n}\n\n\n# Checks if all of the required environment\n# variables are set. If one of them isn't,\n# echoes a text explaining which one isn't\n# and the name of the ones that need to be\ncheck_env_vars_set() {\n  for required_env_var in ${REQUIRED_ENV_VARS[@]}; do\n    if [[ -z \"${!required_env_var}\" ]]; then\n      echo \"Error:\n    Environment variable '$required_env_var' not set.\n    Make sure you have the following environment variables set:\n      ${REQUIRED_ENV_VARS[@]}\nAborting.\"\n      exit 1\n    fi\n  done\n}\n\n\n# Performs the initialization in the already-started PostgreSQL\n# using the preconfigured POSTGRE_USER user.\ninit_user_and_db() {\n  psql -v ON_ERROR_STOP=1 --username \"$POSTGRES_USER\" \u003c\u003c-EOSQL\n     CREATE USER $FILLA_DB_USER WITH PASSWORD '$FILLA_DB_PASSWORD';\n     CREATE DATABASE $FILLA_DB_DATABASE;\n     GRANT ALL PRIVILEGES ON DATABASE $FILLA_DB_DATABASE TO $FILLA_DB_USER;\nEOSQL\n}\n\n# Executes the main routine with environment variables\n# passed through the command line. We don't use them in\n# this script but now you know 🤓\nmain \"$@\"\n```\n\n./postgres/Dockerfile.dev\n\n```Dockerfile\nFROM postgres:alpine\n\nADD ./init /docker-entrypoint-initdb.d/\n```\n\n### Nginx path routing\n\n#### default.conf\n\nIn order to setup nginx in the application to route the request off the appropriate backend we're gonna create a file called `default.conf`, this is a very special file to we're gonna added to our nginx image this file is gonna add a little bit of configuration to implement this set of routing routes:\n\n- tell nginx that is an 'upstream' server at client:3000 and server:5000\n- listen on port 80\n- if someone comes to '/' send them to client upstream\n- if someone comes to '/api' send them to server upstream\n\n./nginx/default.conf\n\n```conf\nupstream client {\n    # notice ;\n    server client:3000;\n}\n\nupstream api{\n    server api:5000;\n}\n\nserver {\n    listen 80;\n\n    location / {\n        proxy_pass http://client;\n    }\n\n    # react dev server request not handled WebSocket connection to ws Error\n    location /sockjs-node {\n        proxy_pass http://client;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"Upgrade\";\n    }\n\n    location /api {\n        # rewrite will remove /api/ from request\n        rewrite /api/(.*) /$1 break;\n        proxy_pass http://api;\n    }\n}\n```\n\n#### Build a custom nginx image from\n\n./nginx/Dockerfile.dev\n\n```dockerfile\nFROM nginx\n\n# override the default.conf\nCOPY ./default.conf /etc/nginx/conf.d/default.conf\n```\n\n### A continuous integration and deployment workflow for multiple images\n\n- push code to git repository (in this case github)\n- travis automatically pulls the codes\n- travis builds a test image, test code\n- travis builds a production image\n- travis pushes built production image to docker hub\n- travis push project to AWS EB\n- AWS EB pulls images from docker hun, deploys\n\n### Nginx on client\n\n./client/nginx/default.conf\n\n```conf\nserver {\n    listen 3000;\n\n    location / {\n        root /usr/share/nginx/html; # /usr\n        index index.html index.htm;\n        try_file $url $url/ /index.html; # *** make nginx works correctly with react-router *** for some reason this line have an issue with k8s pod configuration so i deleted this line on tajpouria/multi-client:v3\n    }\n}\n```\n\n./client/Dockerfile\n\n```Dockerfile\nFROM node:alpine as builder\nWORKDIR /usr/app\nCOPY ./package.json .\nRUN npm i\nCOPY . .\nRUN npm run build\n\nFROM nginx\nEXPOSE 3000\nCOPY ./nginx/default.conf /etc/nginx/conf.d/default.conf\nCOPY --from=builder /usr/app/build /usr/share/nginx/html\n```\n\n### Pushing image to docker hub\n\n- login to docker\n\n  \u003e docker login\n\n- push an image to docker hub\n\n  \u003e docker push IMAGE_ID/TAG\n\n```yml\nsudo: required\nservices:\n  - docker\nbefore_install:\n  - docker build -t tajpouria/react-app -f ./client/Dockerfile.dev ./client # *** make sure to specify client directly as build context\nscript:\n  - docker run tajpouria/react-app npm run test -- --coverage\n\nafter_success:\n  - docker build -t tajpouria/multi-nginx ./nginx\n  - docker build -t tajpouria/multi-postgres ./postgres\n  - docker build -t tajpouria/multi-worker ./worker\n  - docker build -t tajpouria/multi-server ./server\n  - docker build -t tajpouria/multi-client ./client\n  # login to docker-cli (using travis environment variables)\n  # retrieve the docker password from environment variable and essentially emit that as input to the next command stdin channel\n  - echo \"$DOCKER_PASSWORD\" | docker login -u \"$DOCKER_ID\" --password-stdin\n  # take those images and push them to docker hub\n  - docker push tajpouria/multi-nginx\n  - docker push tajpouria/multi-postgres\n  - docker push tajpouria/multi-worker\n  - docker push tajpouria/multi-server\n  - docker push tajpouria/multi-client\n```\n\n# Kubernetes\n\n## Why use kubernetes\n\nIf we were use kubernetes we can have additional machines running containers and we could had a lot of control over whats these additional machines were doing or what container they were running\n\n### Kubernetes cluster\n\nA **cluster** in world of kubernetes is an assembly of **master** and one or more **nodes**\n\n- a node is a virtual machine or a physical computer that use to run some number of different containers\n- in world of kubernetes are these nodes that have been created is manged by something named master, master contains a sets of program on it that control what each of these nodes is running at any given time\n\n#### Kubernetes is a system for running many different containers over multiple different machines and used when you need to run many different containers with different images\n\n### Kubernetes in development and production\n\nFor running kubernetes in development environment we using a program called **minikube**\n\n- minikube is a command line tool and it's purpose is to setup tiny cluster on your local machine\n\nwhen we start using kubernetes on production environment we very frequently use what are called **manage solutions**\n\n- managed solutions are referenced to outside cloud provides such as Amazon Elastic Container Service for Kubernetes (EKS), Google Cloud Kubernetes Engine (GKS) and etc, that will setup entire kubernetes cluster for you\n\n- in order to interact with this cluster we're going to use a program name **kubectl**\n\n## Installing\n\nThese instructions were tested on a laptop with the desktop version of Linux Mint 19 Cinnamon installed. Current Ubuntu desktop version's setup should be the same. Your experience may vary if using an RHEL / Arch / Other distribution or non desktop distribution like Ubuntu server, or lightweight distributions which may omit many expected tools.\n\n- Install VirtualBox:\n\nFind your Linux distribution and download the .deb package, using a graphical installer here should be sufficient. If you use a package manager like apt to install from your terminal, you will likely get a fairly out of date version.\n\nhttps://www.virtualbox.org/wiki/Linux_Downloads\n\nAfter installing, check your installation to make sure it worked:\n\n\u003e VBoxManage —version\n\n**For some reason Virtual box not worker for me and I used KVM instead:**\n\n- Install KVM:\n\nhttps://help.ubuntu.com/community/KVM/Installation :\n\n\u003e sudo apt-get install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils\n\nhttps://askubuntu.com/questions/1050621/kvm-is-required-to-run-this-avd :\n\n\u003e sudo adduser \\$USER kvm\n\nhttps://minikube.sigs.k8s.io/docs/reference/drivers/kvm2/ :\n\n\u003e virt-host-validate\n\n**Make sure no test failed**\n\n\u003e minikube start --vm-driver=kvm2\n\nAs an alternative you can use (or maybe you have to use) KVM instead of VirtualBox. Here are some great instructions that can be found in this post (Thanks to Nick L. for sharing):\n\nhttps://computingforgeeks.com/install-kvm-centos-rhel-ubuntu-debian-sles-arch/\n\n- Install Kubectl\n\nIn your terminal run the following:\n\n\u003e curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl\n\n\u003e sudo mv ./kubectl /usr/local/bin/kubectl\n\nCheck your Installation:\n\n\u003e kubectl version\n\nSee also official docs:\nhttps://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-on-linux\n\n- Install Minikube\n\nIn your terminal run the following:\n\n\u003e curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 \u0026\u0026 chmod +x minikube\n\n\u003e sudo install minikube /usr/local/bin\n\nCheck your installation:\n\nminikube version\n\n- Start Minikube:\n\nhttps://github.com/kubernetes/minikube/issues/2412 :\n\n\u003e minikube delete\n\n\u003e minikube start\n\n\u003e minikube start --memory 4096 # Start with 4 G of ram\n\n\u003e minikube dashboard\n\nin order to stop VM\n\n\u003e minikube stop\n\nSee also official docs:\n\nhttps://kubernetes.io/docs/tasks/tools/install-minikube/\n\n- Gets the status of a local kubernetes cluster:\n\n\u003e minikube status\n\n- display cluster info\n\n\u003e kubectl cluster-info\n\n- VM ip\n\n\u003e minikube ip\n\n### Mapping existing knowledge\n\n|                         docker-compose                         |                    kubernetes                    | get a simple container running on our local kubernetes cluster running |\n| :------------------------------------------------------------: | :----------------------------------------------: | :--------------------------------------------------------------------: |\n| Each entry can optionally get docker-compose to build an image | Kubernetes expect all images to already be built |              Make sure our images is hosted on docker hub              |\n|       Each entry represent a container we want to create       |  One config file per _object_ we want ot create  |              Make one config file to create the container              |\n|     Each entry defines the networking requirements (ports)     |    We have to manually set up all networking     |               Make one config file to set up networking                |\n\n### Adding configuration\n\n#### terminology\n\n**Config file describe the containers(or objects in k8s) we want**\n\nthe **object** in k8s world is a thing!! that will create in our cluster to make it behave the way we expect\n\n- Pod: After we run `minikube start` it will create a virtual machine on computer we refer to that machine as a **node** we'll use this node to run different objects, one of this most basic object that we gonna create is refer as a **Pod**, a pod essentially is a grouping of very **closely**Jjk related container(s) with a very common purpose\n\n- Service : we `Service` object type we we're gonna set up networking in a k8s cluster\n\n- NodePort: is a **sub object type of Service object type** every time a request coming to **kubeProxy**(the single window to communicate to world outside of the node) then it will reach the nodePort and nodePort will link it to a container inside a Pod _nodePort is only uses for development purposes_\n\n./simplek8s/client-pod.yml\n\n```yml\napiVersion: v1 # Each API version defines a different set of object we can use\nkind: Pod # Specify the object type we want to create, object serve different purpose for e.g. Pod: running a container, Service: networking\nmetadata:\n  name: client-pod # the name of pod that get created\n  labels:\n    component: web # label that Pod to be able to select that from Service\nspec:\n  containers:\n    - name: client\n    image: tajpouria/multi-client\n      ports:\n      - containerPort: 3000 # on this container we want to expose port 3000 to the outside world\n```\n\n./simplek8s/client-node-port.yml\n\n```yml\napiVersion: v1\nkind: Service\nmetadata:\n  name: client-node-port\nspec:\n  type: NodePort # exposes a container to the outside world(only good for development purposes)\n  ports:\n    - port: 3000 # the port that other Pod in our cluster can access to this Pod targetPort: 3000 # the port inside this Pod that we going open up traffic to nodePort: 31515 # the port we're going to use outside the node (in browser) in order to access to access the Pod ***(default: random number between 30000 and 32767)\n       selector:\n    component: web # select web pod by it's label\n```\n\n- Feed the config file to kubctl\n\n\u003e kubectl apply -f \\\u003cpath to the file or the folder contains all config files\\\u003e\n\n- Retrieve information about a running object\n\n\u003e kubectl get \\\u003cobject name\\\u003e\n\ne.g. print the status of all running pods\n\n\u003e kubectl get pods\n\ne.g. print the status of all services\n\n\u003e kubectl get services\n\ne.g. print the status of all persistent volumes\n\n\u003e kubectl get pv\n\ne.g. print the status of all persistent volumes claims\n\n\u003e kubectl get pvc\n\ne.g. print secrets\n\n\u003e kubectl get secrets\n\n- Show description of a specific resource or group of resource\n\n\u003e kubectl describe \\\u003cobject type\\\u003e \\\u003cobject name\\\u003e\n\ne.g a pod description\n\n\u003e kubectl describe client-pod\n\n- Delete an object\n\n1.  delete by config file\n    \u003e kubectl delete -f \\\u003cpath to the file that used to create that object \\\u003e\n        e.g delete the client-pod\n    \u003e kubectl delete client-pod.yml\n2.  delete by object type\n    \u003e kubectl delete deployment client-deployment\n\n- Get Pod logs\n\n\u003e kubectl logs \\\u003cPod name\\\u003e\n\n- get all the different options that k8s has to create a persistent volume\n\n\u003e kubectl get storageclass\n\n#### After applying Pod and nodePort configuration the node is available on NODE_IP:nodePort:\n\nNODE_IP:\n\n\u003e minikube ip\n\nnodePort: 31515\n\n### the entire deployment workflow\n\n- When we run `kubectl apply -f \u003cfilename\u003e` the file is taken and pass into master\n- On the master kube-apiServer will read configuration file and interpret it in some fashion\n- kube-apiServer will update the cluster status based upon of configuration file and node(s) status\n- kube-apiServer will tell node(s) that which container and how much copy of it should run\n- each node have a copy of docker into it and it will use it to reach into docker hub to create container(s) of it\n- kube-apiServer will update the status\n\n## Maintaining sets of container with deployment\n\n### Pods downwards\n\nWith the Pods configured as container wrapper there is just a few fields available that we can changed and maintain:\n\n| Pod Configuration | Able to change |\n| :---------------: | :------------: |\n|    containers     |       no       |\n|       name        |       no       |\n|       ports       |       no       |\n|       image       |      yes       |\n\nAnd this is kind of downward for Pods and because of this reason and some other reason Pods is only appropriate for development purposes\n\n### Deployment\n\nDeployment is a kind of object type that help us to:\n\n- runs and manage a sets of identical Pods one or more\n- monitoring the state of Pods and change it if it's necessary\n- is appropriate of both development and production\n\n./simplek8s/client-deployment.yml\n\n```yml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: client-deployment\nspec:\n  replicas: 1 # the number of Pods that this Deployment is going to create\n  selector: # uses by Deployment to handle over Pods after it's has been created\n    matchLabels:\n      component: web\n  template: # configuration of every single Pod that will created by this deployment\n    metadata:\n      labels:\n        component: web\n    spec:\n      containers:\n        - name: client\n          image: tajpouria/multi-client\n          ports:\n            - containerPort: 3000\n```\n\n_delete client-pod_\n\n\u003e kubectl delete -f client-pod.yml\n\n\u003e kubectl apply -f client-deployment.yml\n\n### Update image version\n\nHere's the steps we going through:\n\n- Tag the image with a version number and push it to docker hub\n- Run the kubectl command that forcing that deployment to use new the new image version:\n\n\u003e kubectl set image \\\u003cobject type\\\u003e/\\\u003cobject name\\\u003e \\\u003ccontainer name\\\u003e=\\\u003cnew image to use\\\u003e\n\ne.g.\n\n\u003e kubectl set image Deployment/client-deployment client=tajpouria/multi-client:v2\n\n### Configure the VM machine to use your dockerServer\n\nIn order to access the **dockerServer instance on VM(node)** from your **current terminal** window use following command:\n\n\u003e eval \\$(minikube docker-env)\n\n_this command exports a sets of env-variables that uses by docker to decide which containers it should try to connect to_\n\n**this configuration only works on your current terminal window**\n\n## A multi container Application with k8s\n\n[Following description project repository **/branch k8s**](https://github.com/tajpouria/Docker-Multiple-Container-Test/tree/k8s)\n\n![](./assets/multi-container-k8s.png)\n\n### NodePort vs ClusterIP\n\nIn world of k8s we use services to setup networking in a cluster; NodePort and ClusterIP are both kind of services **NodePort** is uses whenever we going to setup networking between a Pod and **outside world** however **ClusterIP** is using for setup networking between a Pod and **other cluster objects**\n\n### ClusterIp Service\n\n./k8s/client-cluster-ip-service.yml\n\n```yml\napiVersion: v1\nkind: Service\nmetadata:\n  name: client-cluster-ip-services\nspec:\n  type: ClusterIP\n  selector:\n    component: web\n    ports:\n      - port: 3000 # other objects can access this ClusterIP through this port\n        targetPort: 3000 # Pod port\n```\n\n### Combining multiple config file into one\n\n./k8s/api-config.yml\n\n```yml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: api-deployment\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      component: api\n  template:\n    metadata:\n      labels:\n        component: api\n    spec:\n      containers:\n        - name: api\n          image: tajpouria/multi-api\n          ports:\n            - containerPort: 5000\n--- # *** separate each config file with 3 dashes\napiVersion: v1\nkind: Service\nmetadata:\n  name: api-cluster-ip-services\nspec:\n  type: ClusterIP\n  selector:\n    component: api\n  ports:\n    - port: 5000\n      targetPort: 5000\n```\n\n### K8s persistence volume claim\n\nK8s volumes is about how to persisting data outside of a container because that data is something that we care about and we want to persisted across the restarts or terminations of a given container\n\n#### The word Volumes in world of k8s is an Object that essentially allows a container to persistent data at the Pod level\n\n#### In this section we're not gonna use k8s's Volumes we want use pe Persistent Volume Claim and Persistent Volume\n\n### K8s's Volumes vs PersistentVolume\n\n![](assets/k8s_volume_vs_pesistentVolume.png)\n\n### Persistent Volume Claim (PVC) vs Persistent Volume (PV)\n\nThe **Persistent Volume Claim is an advertizement of options** we can ask for one those options inside our Pod config then k8s is going to look the existing store of **Persistent Volume** and it's going to either give you a volume that's been created ahead of time or attempt to create one on the fly\n\n### terminology\n\n- accessMods:\n  1. ReadWriteOnce: can read and write by a single node at a time\n  2. ReadWriteMany: can read by multiple node at the same time\n  3. ReadOnlyMany: can read and write by multiple node at the same time\n\n./k8s/database-persistent-volume-claim.yml\n\n```yml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: database-persistent-volume-claim\nspec:\n  accessMods:\n    - ReadWriteOnce\n  resources:\n    requests:\n      storage: 2gi\n```\n\n### Designing a PVC in Pod Template\n\n./k8s/postgres-deployment.yml\n\n```yml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: postgres-deployment\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      component: postgres\n  template:\n    metadata:\n      labels:\n        component: postgres\n    spec:\n      volumes: # allocate the storage\n        - name: postgres-storage\n          persistentVolumeClaim:\n            claimName: database-persistent-volume-claim # name of created PV on node\n      containers:\n        - name: postgres\n          image: tajpouria/multi-postgres\n          ports:\n            - containerPort: 5432\n          volumeMounts: # using the storage\n            - name: postgres-storage # the name of storage\n              mountPath: /var/lib/postgresql/data # store this path (in this case postgres default data storing path)\n              subPath: postgres # sore the data inside a folder name postgres on the actual PV (postgres needs that!!)\n          env:\n            - name: PGPASSWORD # postgres will use this password (PGPASSWORD) as default password\n              valueFrom:\n                secretKeyRef:\n                  name: pgpassword\n                  key: PGPASSWORd\n```\n\n### Environment variables in k8s\n\nSecurely stores a piece of information in the cluster, such as a database password\n\n\u003e kubectl create secret generic \\\u003csecret_name\\\u003e --from-literal key=value\n\ne.g.\n\n\u003e kubectl create secret generic pgpassword --from-literal PGPASSWORD=1234asdf\n\n#### Constant variables\n\n```yml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: api-deployment\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      component: api\n  template:\n    metadata:\n      labels:\n        component: api\n    spec:\n      containers:\n        - name: api\n          image: tajpouria/multi-api\n          ports:\n            - containerPort: 5000\n          env: # environment variables\n            - name: REDISHOST\n              value: redis-cluster-ip-service # *** once you needs other pods set pods_name as URL\n            - name: REDISPORT\n              value: \"5432\" # make sure pass string (Error: cannot convert int64 into sting!)\n            - name: PGPASSWORD\n              valueFrom: # getting the key from SecretObject\n                secretKeyRef:\n                  name: pgpassword # the name of the secret\n                  key: PGPASSWORD # a secret can have multiple keys and we should specify which key we want\n```\n\n## Handling traffic with ingress controller\n\nIngress is a type of services that is going to give some amount of traffic into our application\n\n**In this case we're gonna use a project name [ kubernetes/ingress-nginx ](https://github.com/kubernetes/ingress-nginx)**\n\n### How ingress services created behind the scenes\n\n- create a config file and pass to KubeCTL in order to create an ingress service\n- KubeCTL will create an `object` inside of kubernetes called `controller`\n- this object will compare current state and desired state\n- then object will create a nginx Pod that have many particular rules that make sure the traffic that comes in will sent of to appropriate service\n\n### Ingress-nginx installation guide https://kubernetes.github.io/ingress-nginx/deploy/\n\nThe following Mandatory Command is required for all deployments:\n\n\u003e kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml\n\nminikube:\n\n\u003e minikube addons enable ingress\n\n### Configure ingress-service.yml\n\n./k8s/ingress-service.yml\n\n```yml\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n  name: ingress-service\n  annotations:\n    kubernetes.io/ingress.class: nginx\n    nginx.ingress.kubernetes.io/rewrite-target: /\nspec:\n  rules:\n    - http:\n        paths:\n          - path: /\n            backend:\n              serviceName: client-cluster-ip-service\n              servicePort: 3000\n          - path: /api/\n            backend:\n              serviceName: server-cluster-ip-service\n              servicePort: 5000\n```\n\n## Sundry\n\n### Node process exit status codes\n\n- 0: we exited and everything is OK\n- 1, 2, 3, etc: we exited because something went wrong\n\n### Redis\n\n#### pub/sub\n\n```typescript\nconst client = redis.createClient({\n  host,\n  key,\n  retry_strategy: () =\u003e 1000, // if ever loses the connection it's automatically try to reconnect every one second\n});\n\nconst sub = client.duplicate(); // Duplicate all current options and return a new redisClient instance, to send regular command to redis while in subscriber mode, just open another connection with a new client.\nsub.on(\"message\", (channel, message) =\u003e {\n  redisClient.hset(\"values\", message, \"hello\"); // sets field in the hash stored at key to value e.g redis-cli\u003eHSET my hash field1 \"hello\" redis-cli\u003eHGET hash field1\n});\nsub.subscribe(\"insert\");\n\nconst publisher = client.duplicate();\npublisher.publish(\"insert\", index);\n```\n\n#### hgetall\n\nGet the all values inside a hash\n\n```typescript\nredis.hgetall(\"values\", (err, values) =\u003e values);\n```\n\n### travis\n\n#### Safelisting or Blocklisting Branches\n\n```yml\n# blocklist\nbranches:\n  except:\n  - legacy\n  - experimental\n\n# safelist\nbranches:\n  only:\n  - master\n  - stable\n```\n\n# Istio\n\nAn Istio service mesh is logically split into a data plane and a control plane.\n\nThe data plane is composed of a set of intelligent proxies (Envoy) deployed as sidecars. These proxies mediate and control all network communication between microservices. They also collect and report telemetry on all mesh traffic.\n\nThe control plane manages and configures the proxies to route traffic.\n\n![control plane and data plane](https://istio.io/latest/docs/ops/deployment/architecture/arch.svg)\n\n## Setup Istio control plane\n\n### Warmup setup way: Using pre-generated K8s config\n\n1. Setup Istio control plane\n\n[istio-init.yaml](./isitio-fleetman/init-istio/istio-init.yaml): Initialize Istio custom resource definitions\n\n\u003e k apply -f istio-init.yaml\n\n[istio-minikube.yaml](./isitio-fleetman/init-istio/istio-minikube.yaml): Create control plane components\n\n\u003e k apply -f istio-minikube.yaml\n\n2. Setup kiali username and passprase secret\n\n[kiali-secret.yml](./isitio-fleetman/init-istio/kiali-secret.yml)\n\n\u003e k apply -f kiali-secret.yml\n\n3. Setup Istio data plane\n\nThere are multiple ways of doing this but here we will do it by setting a label on working namespace and let the istio to attach the sidecar proxies:\n\n\u003e k label namespace default istio-injection=enabled\n\n\u003e k describe ns default\n\n```sh\nName:         default\nLabels:       istio-injection=enabled\nAnnotations:  \u003cnone\u003e\nStatus:       Active\n\nNo resource quota.\n\nNo LimitRange resource.\n```\n\n### Istio control plane components\n\n- Galley: Reads K8s config (or other orchestration platform) and convert it in the internal format that istio understands.\n\n- Pilot: Receive formmated configuarion and propagate it across the proxies\n\n- Citadel: Managing TLS/SSL certifciates e.g. secure cominucation between proxies\n\n### What is required for distributed tracing with Istio?(https://istio.io/latest/faq/distributed-tracing/#how-to-support-tracing)\n\nThe application needs to propagate the trace context. For example in case of an HTTP request you need to read tracing headers (**x-request-id**, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, x-b3-sampled, x-b3-flags, b3) and send them alongside with the response.\n\nAs a side note, the `x-request-id` will be generated by sidecard proxies and attacted to the request if it's not exists.\n\n### Traffic management\n\n- Kiali uses `app` label in app graph and `version` label in version graph\n\n```yml\nmetadata:\n  labels:\n    app: staff-service\n    version: safe\n---\nmetadata:\n  labels:\n    app: staff-service\n    version: risky\n```\n\n![](assets/kiali-uses-lables.png)\n\n### Istio virtual service\n\nvs:\n\nVirtual services enables us to configure custom routing to the service mesh.\n\nVirtual services are managed by pilot and allows us to change the side-car proxies configuration in a dynamic fashion and manage the incoming traffic that way.\n\n_Despite the name virtual services and services (K8s's services) aren't really related_\n\ndr:\n\nDefining which pod should be a part of each subset\n\n## VS and DR configuration\n\n```yaml\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n  name: fleetman-staff-service # \"Just\" a name for the virtual service\n  namespace: default\nspec:\n  hosts:\n    - fleetman-staff-service.default.svc.cluster.local # The service DNS (i.e the regular K8s service) name that we're applying routing rules to. (In this case the name of the cluster IP)\n  http:\n    - route:\n        - destination:\n            host: fleetman-staff-service.default.svc.cluster.local # The target service DNS name (In this case the name of the cluster IP)\n            subset: safe # Pointing to the name that have been defined by destination rule\n          weight: 0 # Should be integer and not floating point numbers\n        - destination:\n            host: fleetman-staff-service.default.svc.cluster.local # The target service DNS name\n            subset: risky\n          weight: 100 # Should be integer and not floating point number\n---\napiVersion: networking.istio.io/v1beta1\nkind: DestinationRule\nmetadata:\n  name: fleetman-staff-service # \"Just\" a name for destination rule\n  namespace: default\nspec:\n  host: fleetman-staff-service.default.svc.cluster.local # The target service DNS name (In this case the name of the cluster IP)\n  trafficPolicy: ~\n  subsets:\n    - labels: # This is actually a pod SELECTOR\n        version: safe # The target pod should have this label\n      name: safe\n    - labels: # This is actually a pod SELECTOR\n        version: risky # The target pod should have this label\n      name: risky\n```\n\n### Load balancing\n\n### Session affinity (Sticky session) load balancing\n\nIn the following example we uses request header as input of consistent hashing load balancer.\n\n```yml\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n  name: fleetman-staff-service\n  namespace: default\nspec:\n  hosts:\n    - fleetman-staff-service.default.svc.cluster.local\n  http:\n    - route:\n        - destination:\n            host: fleetman-staff-service.default.svc.cluster.local\n            subset: all-staff-service\n          weight: 100\n---\napiVersion: networking.istio.io/v1beta1\nkind: DestinationRule\nmetadata:\n  name: fleetman-staff-service\n  namespace: default\nspec:\n  host: fleetman-staff-service.default.svc.cluster.local\n  trafficPolicy:\n    loadBalancer:\n      consistentHash:\n        httpHeaderName: \"x-myval\"\n  subsets:\n    - labels:\n        app: staff-service\n      name: all-staff-service\n```\n\n**Keep in mind you need to propaget the target header in order to loadbalancer to works:**\n\n![](assets/lb-header-propagation.png)\n\n**Sticky session load balancing and weighted routing will not works together. For example in following configuation that uses source IP as the input of consistent hashing algorithem, requets does not always ends up getting routed to a specific upstream:**\n\n```yml\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n  name: fleetman-staff-service\n  namespace: default\nspec:\n  hosts:\n    - fleetman-staff-service.default.svc.cluster.local\n  http:\n    - route:\n        - destination:\n            host: fleetman-staff-service.default.svc.cluster.local\n            subset: safe\n          weight: 50\n        - destination:\n            host: fleetman-staff-service.default.svc.cluster.local\n            subset: risky\n          weight: 50\n---\napiVersion: networking.istio.io/v1beta1\nkind: DestinationRule\nmetadata:\n  name: fleetman-staff-service\n  namespace: default\nspec:\n  host: fleetman-staff-service.default.svc.cluster.local\n  trafficPolicy:\n    loadBalancer:\n      consistentHash:\n        useSourceIp: true\n  subsets:\n    - labels:\n        version: safe\n      name: safe\n    - labels:\n        version: risky\n      name: risky\n```\n\n### Gateways\n\nIn Istio we're using Gateway instead of traditional Ingress. Here's how request routed to out the application using Istio gateways:\n\n- A client makes a request on a specific port.\n- The Load Balancer listens on this port and forwards the request to one of the workers in the cluster (on the same or a new port).\n- Inside the cluster the request is routed to the Istio IngressGateway Service which is listening on the port the load balancer forwards to.\n- The Service forwards the request (on the same or a new port) to an Istio IngressGateway Pod (managed by a Deployment).\n- The IngressGateway Pod is configured by a Gateway (!) and a VirtualService.\n- The Gateway configures the ports, protocol, and certificates.\n- The VirtualService configures routing information to find the correct Service\n- The Istio IngressGateway Pod routes the request to the application Service.\n- And finally, the application Service routes the request to an application Pod (managed by a deployment).\n\n![](assets/istio-networking.png)\n\nGateways will strictly will be used to configure Istio ingress gateway which will spin up on Istio startup\n\n### Gateway configuration\n\nInside the configuration we can specify for example what kind of requests that should routed inside the cluster:\n\n```yml\napiVersion: networking.istio.io/v1beta1\nkind: Gateway\nmetadata:\n  name: ingress-gateway # Name of the gateway later on\nspec:\n  selector:\n    istio: ingressgateway # Select the ingress gateways which confiugarion should applied on for example `istio: gateway` is the default label of istio gateway\n  servers:\n    - port:\n        number: 80 # Allow HTTP requests to enter\n        name: http\n        protocol: HTTP\n      hosts:\n        - \"*\" # Incoming requests hosts (In this case requests that comes from an external origin)\n```\n\nAfter requests get routed inside the cluster, We're need a way to route them into a specific service. This part of configuration will happen inside the target's virtual service configuration:\n\nFor example in following configuration we're doing a weighted routing\n\n```yml\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n  name: webapp-vs\n  namespace: default\nspec:\n  gateways:\n    - ingress-gateway # Specify the name of gatway\n  hosts:\n    - \"*\" # Incoming request host\n  http:\n    - route:\n        - destination:\n            host: fleetman-webapp.default.svc.cluster.local\n            subset: original\n          weight: 90\n        - destination:\n            host: fleetman-webapp.default.svc.cluster.local\n            subset: experimental\n          weight: 10\n```\n\nAnd in following configuration we're doing a Uri prefix routing:\n\n```yml\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n  name: webapp-vs\n  namespace: default\nspec:\n  gateways:\n    - ingress-gateway\n  hosts:\n    - \"*\"\n  http:\n    - match:\n        - uri:\n            prefix: /experimental\n      route:\n        - destination:\n            host: fleetman-webapp.default.svc.cluster.local\n            subset: experimental\n    - match:\n        - uri:\n            prefix: /\n      route:\n        - destination:\n            host: fleetman-webapp.default.svc.cluster.local\n            subset: original\n```\n\n## Dark release\n\nIn the following example we're going to configure the virtual service in a way that:\nif incoming request contains `x-my-header: canary` we should response with experimental version of webapp\notherwise respond with original version.\n\n```yml\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n  name: fleetman-webapp\n  namespace: default\nspec:\n  hosts:\n    - \"*\"\n  gateways:\n    - httpbin-gateway\n  http:\n    - name: \"match-canary-header\" # Name is optional and will be used for logging purposes\n      match: # If\n        - headers:\n            x-my-header:\n              exact: canary\n      route: # Then\n        - destination:\n            host: fleetman-webapp\n            subset: experimental\n\n    - name: \"catch-all\" # Catch all (If not matches with upper blocks this rule will be applied)\n      route:\n        - destination:\n            host: fleetman-webapp\n            subset: original\n```\n\nBare in mind this implementation requires header propagation\n\n## Fault injection\n\nDeliberately inject like aborting from responding or responding with delay in order to test the system fault tolerance\n\nAbort fault:\n\n```yaml\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n  name: fleetman-vehicle-telemetry\n  namespace: default\nspec:\n  hosts:\n    - fleetman-vehicle-telemetry.default.svc.cluster.local\n  http:\n    - fault:\n        abort:\n          httpStatus: 503\n          percentage:\n            value: 50.0 # 50 percent of the time respond with 503\n      route:\n        - destination:\n            host: fleetman-vehicle-telemetry.default.svc.cluster.local\n```\n\nDelay fault:\n\n```yaml\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n  name: fleetman-vehicle-telemetry\n  namespace: default\nspec:\n  hosts:\n    - fleetman-vehicle-telemetry.default.svc.cluster.local\n  http:\n    - fault:\n        delay:\n          fixedDelay: 10s\n          percentage:\n            value: 100.0 # 100 percent of the time respond with 10 seconds delay\n      route:\n        - destination:\n            host: fleetman-vehicle-telemetry.default.svc.cluster.local\n```\n\n## Circuit breaker (Outlier detection)\n\n```yml\napiVersion: networking.istio.io/v1beta1\nkind: DestinationRule\nmetadata:\n  name: staff-service-circuit-breaker\nspec:\n  host: \"fleetman-staff-service.default.svc.cluster.local\" # This is the name of the k8s service that we're targeting\n\n  # host: \"*.default.svc.cluster.local\" Also viable to use wildcards for example in this case it means to apply circuit breaker to all services that exists in default name space\n\n  trafficPolicy: # Props description: https://istio.io/latest/docs/reference/config/networking/destination-rule/#OutlierDetection\n    outlierDetection: # Circuit Breakers HAVE TO BE SWITCHED ON\n      maxEjectionPercent: 100\n      consecutive5xxErrors: 2\n      interval: 10s\n      baseEjectionTime: 30s\n```\n\n## Mutual TLS\n\nIstio **automatically** configures workload sidecars to use mutual TLS when calling other workloads. By default, Istio configures the destination workloads using `PERMISSIVE` mode. When `PERMISSIVE` mode is enabled, a service can accept both plain text and mutual TLS traffic. In order to only allow mutual TLS traffic, the configuration needs to be changed to `STRICT` mode.\n\nIn order to enforce mutual TLS (enable STRICT mode) in a namespace uer `PeerAuthentication` CRD provided by Istio:\n\n```yml\n# This will enforce that ONLY traffic that is TLS is allowed between proxies\napiVersion: \"security.istio.io/v1beta1\"\nkind: \"PeerAuthentication\"\nmetadata:\n  name: \"default\"\n  namespace: \"istio-system\"\nspec:\n  mtls:\n    mode: STRICT\n```\n\n## IstioCTL\n\n### Using built-in configuration profiles\n\n\u003e istioctl manifest apply --set profile=demo\n\n[List of profiles](https://istio.io/latest/docs/setup/additional-setup/config-profiles/)\n\n**Use default profile for production. The demo profile does not have allocate enough amount of resources to run Istio on production comfortably**\n\n### Adding addons\n\nExample enabling Kiali and Grafana\n\n\u003e istioctl manifest apply --set profile=demo --set addonComponents.kiali.enabled=true --set addonComponents.kiali.enabled=true --set addonComponents.grafana.enabled=true\n\n### Output profiles\n\n\u003e istioctl profile dump default \u003e default-profile.yaml\n\nThen you can apply this file to cluster using istioctl\n\n\u003e istioctl manifest apply -f default-profile.yaml\n\n[In not modern K8s clusters like Minikube you're gonna have third party authentication issue for that reason you can use first party authentication using following flag](https://istio.io/latest/docs/ops/best-practices/security/#configure-third-party-service-account-tokens):\n\n\u003e istioctl manifest apply -f default-profile.yaml --set values.global.jwtPolicy=first-party-jwt\n\n## Generate Istio Manifest YAML\n\nDump profile:\n\n\u003e istioctl manifest apply -f raw-default-profile.yaml\n\nGenerate Manifest (Turn into valid K8s configuration then we can apply using `k apply -f` afterwards):\n\n\u003e istioctl manifest generate -f raw-default-profile.yaml --set values.global.jwtPolicy=first-party-jwt \u003e istio-minikube.yaml\n\n## Configure Istio services\n\nIf you want to access the add on components - Kiali, Grafana and Jaeger - through a browser, you should be able to configure NodePorts using the IstioOperator API.\n\nFor example, to switch on Kiali's NodePort, you can use the following:\n\n```yaml\nkiali:\n  enabled: true\n  k8s:\n    replicaCount: 1\n    service:\n      type: NodePort\n      ports:\n        - port: 20001\n          nodePort: 31000\n```\n\nYou can use any nodePort you like - I'm using port 31000 here to be consistent with the port we used on the course yaml.\n\nThis works for Grafana as well.\n\nUnfortunately, I've been unable to get this working for Jaeger. The following block does not work:\n\n```yaml\ntracing:\n  enabled: true\n  k8s:\n    service:\n      type: NodePort\n      ports:\n        - port: 16686\n          nodePort: 31001\n```\n\nI suspect this is an oversight in the release of Istioctl I was using to record (1.5.1). I've contacted the Istio developers and as soon as I get guidance on how to handle this, I will update this lecture and replace with a proper video.\n\nIn the meantime, it's not ideal, but you can manually edit the generated istio-configuration.yaml file to replace the ClusterIP services with NodePorts.\n\nBe careful if you do this - if you re-generate, you will lose your changes - but it's a decent workaround for now at least.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftajpouria%2Fdocker-and-kubernetes-cheat-sheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftajpouria%2Fdocker-and-kubernetes-cheat-sheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftajpouria%2Fdocker-and-kubernetes-cheat-sheet/lists"}