automatically download package when pod restarts - docker

I am again and again downloading and install a package whenever a pod restarts so how can I automate it.
I wanted the pod to automatically install or download a package when the pod restarts.how can I do it in Kubernetes?

Option 1 (best practice):
If you want the package to be downloaded and installed in the container inside of the Pod when it starts, then you must add those download and install instructions to the Dockerfile using the RUN directive.
If you’re using a public image, and not your own custom image, then you’ll want to create a Dockerfile and use the public image as the base image to create and push your own custom Docker image to a image repository. You do this by adding the FROM directive as the first line of the Dockerfile.
There are a ton of tutorials out there on how to build images with Dockerfiles and push them to a repository for use by Kubernetes. Here’s the official documentation from Docker which explains the aforementioned directives and everything else you need to know to create Dockerfiles, build them into Docker images, and push them to a image repository like Docker Hub.
In short, you’ll end up with a Dockerfile that looks something like this, which adds the instructions to download and install the package to a base image:
FROM <base image (i.e. the image you’re currently using)>
RUN <download command>
RUN <install command>
The linked documentation tells you how to build and push a Docker image to a repo, and then it’s just a matter of updating the image field in your Pod manifest.
Now whenever your Pod restarts it will already have the package installed.
Option 2 (anti-pattern, not recommended):
Caution: I'm including this option because OP does not want to use Option 1, so I'm including one possible, theoretical alternative.
You could use an init container to accomplish this. The init container would need to download and install a package for your app container and put it in a mounted emptyDir volume shared by the init container and app container. This work would be done using the command property in the init container.
After your init container runs, your app container can access the package via the mounted shared emptyDir volume.
More about sharing data between containers.
There are several reasons I could think of off the top of my head for why this is an anti-pattern:
It slows down Pod startup time.
Your emptyDir volume is mutable and if you somehow delete or corrupt the package, and your app container (not Pod) crashes, your Pod will crash loop as your init container only runs on Pod restarts, not container restarts.
It unnecessarily complicates your Pod manifest.

A pod should be complete - it shouldn't need to download and install a package. You are essentially trying to do a 'build step' during pod startup, this is almost certainly an anti-pattern.
If the image you are using doesn't contain a package then you should build your own image and deploy it to a docker registry or look for a different docker image that contains your required package.
ericstaples has done a good job of explaining how to roll your own docker image and push it do a docker repository.
If you edit your question and provide the image repo:tag that you are currently using and also the package you want to install then you may receive better responses.

Related

How can I save any changes of containers?

If I have one ubuntu container and I ssh to it and make one file after the container is destroyed or I reboot the container the new file was destroyed because the kubernetes load the ubuntu image that does not contain my changes.
My question is what should I do to save any changes?
I know it can be done because some cloud provider do that.
For example:
ssh ubuntu#POD_IP
mkdir new_file
ls
new_file
reboot
after reboot I have
ssh ubuntu#POD_IP
ls
ls shows nothing
But I want to it save my current state.
And I want to do it automatically.
If I use docker commit I can not control my images because it makes hundreds of images. because I should make images by every changes.
If I want to use storage I should mount /. but kubernetes does not allow me to mount /. and it gives me this error
Error: Error response from daemon: invalid volume specification: '/var/lib/kubelet/pods/26c39eeb-85d7-11e9-933c-7c8bca006fec/volumes/kubernetes.io~rbd/pvc-d66d9039-853d-11e9-8aa3-7c8bca006fec:/': invalid mount config for type "bind": invalid specification: destination can't be '/'
You can try to use docker commit but you will need to ensure that your Kubernetes cluster is picking up the latest image that you committed -
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
This is going to create a new image out of your container which you can feed to Kubernetes.
Ref - https://docs.docker.com/engine/reference/commandline/commit/
Update 1 -
In case you want to do it automatically, you might need to store the changed state or the files at a centralized file system like NFS etc & then mount it to all running containers whenever required with the relevant permissions.
K8s ref - https://kubernetes.io/docs/concepts/storage/persistent-volumes/
Docker and Kubernetes don't work this way. Never run docker commit. Usually you have very little need for an ssh daemon in a container/pod and you need to do special work to make both the sshd and the main process both run (and extra work to make the sshd actually be secure); your containers will be simpler and safer if you just remove these.
The usual process involves a technique known as immutable infrastructure. You never change code in an existing container; instead, you change a recipe to build a container, and tell the cluster manager that you want an update, and it will tear down and rebuild everything from scratch. To make changes in an application running in a Kubernetes pod, you typically:
Make and test your code change, locally, with no Docker or Kubernetes involved at all.
docker build a new image incorporating your code change. It should have a unique tag, often a date stamp or a source control commit ID.
(optional but recommended) docker run that image locally and run integration tests.
docker push the image to a registry.
Change the image tag in your Kubernetes deployment spec and kubectl apply (or helm upgrade) it.
Often you'll have an automated continuous integration system do steps 2-4, and a continuous deployment system do the last step; you just need to commit and push your tested change.
Note that when you docker run the image locally in step 3, you are running the exact same image your production Kubernetes system will run. Resist the temptation to mount your local source tree into it and try to do development there! If a test fails at this point, reduce it to the simplest failing case, write a unit test for it, and fix it in your local tree. Rebuilding an image shouldn't be especially expensive.
Your question hints at the unmodified ubuntu image. Beyond some very early "hello world" type experimentation, there's pretty much no reason to use this anywhere other than the FROM line of a Dockerfile. If you haven't yet, you should work through the official Docker tutorial on building and running custom images, which will be applicable to any clustering system. (Skip all of the later tutorials that cover Docker Swarm, if you've already settled on Kubernetes as an orchestrator.)

How to update my app when I deploy it using docker

I'm deployed a nodejs app using docker, I don't know how to update the deploy after my nodejs app updated.
Currently, I have to remove the old docker container and image when updating the nodejs app each time.
I expect that it's doesn't need to remove the old image and container when I nodejs app updated.
You tagged this "production". The standard way I've done this is like so:
Develop locally without Docker. Make all of your unit tests pass. Build and run the container locally and run integration tests.
Build an "official" version of the container. Tag it with a time stamp, version number, or source control tag; but do not tag it with :latest or a branch name or anything else that would change over time.
docker push the built image to a registry.
On the production system, change your deployment configuration to reference the version tag you just built. In some order, docker run a container (or more) with the new image, and docker stop the container(s) with the old image.
When it all goes wrong, change your deployment configuration back to the previous version and redeploy. (...oops.) If the old versions of the images aren't still on the local system, they can be fetched from the registry.
As needed docker rm old containers and docker rmi old images.
Typically much of this can be automated. A continuous integration system can build software, run tests, and push built artifacts to a registry; cluster managers like Kubernetes or Docker Swarm are good at keeping some number of copies of some version of a container running somewhere and managing the version upgrade process for you. (Kubernetes Deployments in particular will start a copy of the new image before starting to shut down old ones; Kubernetes Services provide load balancers to make this work.)
None of this is at all specific to Node. As far as the deployment system is concerned there aren't any .js files anywhere, only Docker images. (You don't copy your source files around separately from the images, or bind-mount a source tree over the image contents, and you definitely don't try to live-patch a running container.) After your unfortunate revert in step 5, you can run exactly the failing configuration in a non-production environment to see what went wrong.
But yes, fundamentally, you need to delete the old container with the old image and start a new container with the new image.
Copy the new version to your container with docker cp, then restart it with docker restart <name>

Docker - build an environment

After hours of googling I just can't find what I am looking for.
I want to know if I can do the following with Docker: have separate Docker files that can be deployed and shared among a group of devs in my team.
For example:
Container 1 - install of lumen that can also have react installed along with it via command line. Most of our projects are lumen with some needing react/typescript installing too. (being able to use npm install too)
Container 2 - MYSQL/MariaDB with or without data. I understand you could have data in a separate container. I don't mind having MySQL etc in container 1 if I can have the data separate.
The idea is that container 1 can be swapped out as they will represent different projects but the DB data can be a separate container so we can all have our own copy of container 2 and if for whatever reason it get corrupt. we can just re use it.
In Docker, you have different object:
- Dockerfile, it's a file used for building an image
- Image, it's the result of a build using an image definition like a Dockerfile
- Container, it's basically a running image
- Registry, a place where you can store images and share them with other people
So, for your use case, you have different solution, but if I understand your needs, you want to share an image containing lumen and some npm packages to your team? If it's the case, you could build it and push it in a registry.
Your team could use it as is or build custom image based on this one.
For your mysql/mariadb container, you could use the base image and add initialization script (sql or sh files) in /docker-entrypoint-initdb.d.
If you screw the database, you could only remove the container and its volume and start it again.

How to use updated docker image from ACR in AKS

I have a local docker image that was pushed to private Azure Container Registry. Then in Azure Kubernetes Service I have a cluster where I am using this image - from ACR.
Now I wanted to update the image (realised that I needed to install zip and unzip). I started a local container, made changes, committed them and pushed the new image to ACR. Unfortunately, that`s not enough. My pods are still using the previous version of the image, without zip.
Bit more details and what I tried:
Inside the helm chart I am using "latest" tag;
Compared the digest sha of my local "latest" image and what I have in ACR - they are the same;
Started the "latest" container locally (docker run -it --rm -p 8080:80 My-REPO.azurecr.io/MY-IMAGE:latest) - it has zip installed
Deleted existing pods in kubernetes; newly created ones are still missing zip
Deleted the release and recreated it - still nothing.
I am pushing to ACR using docker push MY-REPO.azurecr.io/MY-IMAGE:latest
So my question is - what am I missing? How to properly update this setup?
You should be looking for a setup like this:
Your Docker images have some unique tag, not latest; a date stamp will generally work fine.
Your Helm chart should take the tag as a parameter in the values.yaml file.
You should use a Kubernetes Deployment (not a bare Pod); in its pod spec part specify the image as something like image: MY-REPO.azurecr.io/MY-IMAGE:{{ .Values.tag }}.
When you have a new build, you can helm update --set tag=20190214; this will push an updated Deployment spec to Kubernetes; and that that will cause it to create new Pods with the new image and then destroy the old Pods with the old image.
The essential problem you're running into is that some textual difference in the YAML file is important to make Kubernetes take some action. If it already has MY-IMAGE:latest, and you try to kubectl apply or equivalent the same pod or deployment spec with exactly the same image string, it will decide that nothing has changed and it doesn't need to do anything. Similarly, when you delete and recreate the pod, the node decides it already has a MY-IMAGE:latest image and doesn't need to go off and pull anything; it just reuses the same (outdated) image it already has.
Some best practices related to the workflow you describe:
Don't use a ...:latest image tag (or any other fixed string); instead, use some unique value like a timestamp, source control commit ID, or release version, where every time you do a deployment you'll have a different tag.
Don't use bare pods; use a higher-level controller instead, most often a Deployment.
Don't use docker commit ever. (If your image crashed in production, how would you explain "oh, I changed some stuff by hand, overwrote the image production is using, and forcibly restarted everything, but I have no record of what I actually did"?) Set up a Dockerfile, check it into source control, and use docker build to make images. (Better still, set up a CI system to build them for you whenever you check in.)

Kubernetes Init Containers pip install

I am not sure I am understanding Kubernetes Init containers properly. What i want to do is run an initialization on the pod so that it pip installs some additional libraries that are not in my app container image. Specifically I am wanting to install the Azure storage queue such that i can use it with the standard TensorFlow image.
I set up my init container with the command "pip install azure-storage-queue" and that ran fine however my app container tells me "No module named azure"
Is this not how an init container can be used?
NOTE: I realize i could create a new image with all my prerequisites installed however this is just for development purposes
That's not really how init containers work... Init containers are meant to initialize the pod and the image isn't really shared with other containers that will later run on that pod.
The best solution is to create a new container image including the Python modules you need.
An alternative is to use a command to run in your container that first installs the modules using pip and later runs the script that needs them, that way you can avoid creating a new container image.

Resources