Does it make sense to bake your AMI if you use cfn-init in your cloudformation template? - bootstrapping

I am starting to doubt if I might be missing the whole point of cfn-init. I started thinking that I should bake my AMI used in my cfn template to save time so it doesn't waste time reinstalling all the packages so I can quickly test the next boostrapping steps. But if I have in my cfn-init commands to download awslogs and stream my logs by executing the cfn-init command in my userdata, if I bake that in, my log group will be created, but doesn't the awslog program need to run a fresh command to start streaming logs, it just does not make sense if that command is baked in. Which brings me to my next question, is cfn-init bootstrapping designed (or at least best practice) to run it everytime a new ec2 is spun up, i.e. you cannot or should not bake in the cfn-init part?

Your doubt is very valid and it is purely the design approach and style of working of the devop.
If your cfn-int just accomplishes installing few packages; very well this can be baked in the AMI. As you rightly pointed it would save time and ensure faster stack creation.
However what if you would like to install the latest version of the packages; in That case you can just add the latest flag / keyword to the cfn-init package section. I have used the cfn-init to dynamically to accept the BIOS name of the Active Directory - Domain Controller; so in this case I wouldn't be able to bake that in AMI.
Another place where cfn-init helps is that assume that you have configured 4 packages to be installed; what if you there is a requirement of yet another package to be also installed; in that case - If it is CloudFormation cfn-init - it is another single line of code to be added. If it is AMI - a new AMI approach new AMI has to Baked.
This is purely a trade off.

Related

What is the state of the art running Jenkins - dedicated server or containers?

I've been running Jenkins in container for about 6 months, only one controller/master and no additional nodes, because its not needed in my case, I think. It works OK. However I find it to be a hassle to make changes to it, not because I'm afraid it will crash, but because it takes a long time to build the image (15+ min), installing SDK's etc. (1.3G).
My question is what is the state of the art running Jenkins? Would it be better to move Jenkins to a dedicated server (VM) with a webserver (reverse proxy)?
what-are-the-advantages-of-running-jenkins-in-a-docker-container
Is 15 mins a long time because you make a change, build, find out something is wrong and need to make another change?
I would look at how you are building the container and get all the SDKs installed in the early layers so that rebuilding the container can use those layers from cache and move your layers that change to as late as possible so as little of the container needs rebuilding.
It is then worth looking at image layer caches if you clean your build environment regularly (I use Artifactory)
Generally, I would advocate that as little building is done on the Controller and this is shipped out to agents which are capable of running Docker.
This way you don't need to install loads of SDKs and change your Controller that often etc as you do all that in containers as and when you need them.
I use the EC2 cloud plugin to dynamically spin up agents as and when they are needed. But you could have a static pool of agents if you are not working in a cloud provider.

Advises about how to personal services setup with Helm and Kubernetes

This is more an advises asking than a specific technique question.
I did some search but it's hard to find the exact same issue. If you think it's a duplicate of another one question, please give me some links! :-)
The context
As many developers (I guess), I have one "Ali Baba's cave" server hosting my blog and multiple services: GitLab, Minio, Billing system for my freelance account etc...
All services are setup on an Ubuntu server using differents ways according to the possibilities I have: apt-get install, tar extraction or Capistrano deployments for personal projects.
This is working, but it's a maintenance hell for me. Some project can't be upgraded because a system dependency is conflicted with another one or simply not available on my OS, or an update may have side-effect on some project. For example, a PHP upgrade needed for my personal project completely broke a manually installed PHP service because the new version was not supported.
The needs
I'm currently learning Kubernetes and Helm charts. The goal is to setup a new CoreOS server and a Kubernetes ecosystem with all my apps and projects on it.
With that, I'll be able:
To get rid of maintenance hell with completely independent applications.
To maintain configuration with ease thanks to a simple git project with CI deployment
How to use Helm for that?
I did a test by created a basic chart with helm create my-network, creating a basic nginx app, perfect to add my network homepage!
But now I would like to add and connect some application, let's start with Gitlab.
I found two ways to add it:
Just running the helm upgrade --install gitlab gitalb/gitlab command with a yaml values file for configuration, outside my own chart.
Adding gitlab as a dependency thanks to the requirements.yaml
Both works, giving me the nearly same result.
The first solution seems more "independent" but I don't really know how to build/test it under CI (I would like upgrade automation).
The second allows me to configure all with a single values.yaml files, but I don't know what it is done during a upgrade (Are the upgrade processes of gitlab run during my chart upgrade?) and all in combined onto one "project".
GitLab is an example, but I want to add more of "ready-to-use" apps this way.
What would you advice to me? Solution 1 or 2? And what I should really take care of for both solution, especially for upgrade/backup?
If you have a completely different third solution to propose using Helm, feel free! :-)
Thanks
My experience has generally been that using a separate helm install for each piece/service is better. If those services have dependencies (“microservice X needs a Redis cache”) then those are good things to put in the requirements.yaml files.
A big “chart of charts” runs into a couple of issues:
Helm will flatten dependencies, so if service X needs Redis and service Y also needs Redis, a chart-of-charts setup will install one Redis and let it be shared; but in practice that’s often not what you want.
Separating out “shared” vs. “per-service” configuration gets a little weird. With separate charts you can use helm install -f twice to provide two separate values files, but in a chart-of-charts it’s harder to have a set of really global settings and also a set of per-component settings without duplicating everything.
There’s a standard naming convention that incorporates the Helm helm install --name and the specific component name. This looks normal if it’s service-x-redis, a little weird if it’s service-x-service-x, and kind of strange if you have one global release name the-world-service-x.
There can be good reasons to want to launch multiple independent copies of something, or to test out just the deployment scripting for one specific service, and that’s harder if your only deployment is “absolutely everything”.
For your use case you also might consider whether non-Docker systems management tools (Ansible, Chef, Salt Stack) could reproduce your existing hand deployment without totally rebuilding your system architecture; Kubernetes is pretty exciting but the old ways work very well too.

Docker, update image or just use bind-mounts for website code?

I'm using Django but I guess the question is applicable to any web project.
In our case, there are two types of codes, the first one being python code (run in django), and others are static files (html/js/css)
I could publish new image when there is a change in any of the code.
Or I could use bind mounts for the code. (For django, we could bind-mount the project root and static directory)
If I use bind mounts for code, I could just update the production machine (probably with git pull) when there's code change.
Then, docker image will handle updates that are not strictly our own code changes. (such as library update or new setup such as setting up elasticsearch) .
Does this approach imply any obvious drawback?
For security reasons is advised to keep an operating system up to date with the last security patches but docker images are meant to be released in an immutable fashion in order we can always be able to reproduce productions issues outside production, thus the OS will not update itself for security patches being released. So this means we need to rebuild and deploy our docker image frequently in order to stay on the safe side.
So I would prefer to release a new docker image with my code and static files, because they are bound to change more often, thus requiring frequent release, meaning that you keep the OS more up to date in terms of security patches without needing to rebuild docker images in production just to keep the OS up to date.
Note I assume here that you release new code or static files at least in a weekly basis, otherwise I still recommend to update at least once a week the docker images in order to get the last security patches for all the software being used.
Generally the more Docker-oriented solutions I've seen to this problem learn towards packaging the entire application in the Docker image. That especially includes application code.
I'd suggest three good reasons to do it this way:
If you have a reproducible path to docker build a self-contained image, anyone can build and reproduce it. That includes your developers, who can test a near-exact copy of the production system before it actually goes to production. If it's a Docker image, plus this code from this place, plus these static files from this other place, it's harder to be sure you've got a perfect setup matching what goes to production.
Some of the more advanced Docker-oriented tools (Kubernetes, Amazon ECS, Docker Swarm, Hashicorp Nomad, ...) make it fairly straightforward to deal with containers and images as first-class objects, but trickier to say "this image plus this glop of additional files".
If you're using a server automation tool (Ansible, Salt Stack, Chef, ...) to push your code out, then it's straightforward to also use those to push out the correct runtime environment. Using Docker to just package the runtime environment doesn't really give you much beyond a layer of complexity and some security risks. (You could use Packer or Vagrant with this tool set to simulate the deploy sequence in a VM for pre-production testing.)
You'll also see a sequence in many SO questions where a Dockerfile COPYs application code to some directory, and then a docker-compose.yml bind-mounts the current host directory over that same directory. In this setup the container environment reflects the developer's desktop environment and doesn't really test what's getting built into the Docker image.
("Static files" wind up in a gray zone between "is it the application or is it data?" Within the context of this question I'd lean towards packaging them into the image, especially if they come out of your normal build process. That especially includes the primary UI to the application you're running. If it's things like large image or video assets that you could reasonably host on a totally separate server, it may make more sense to serve those separately.)

DevOps Simple Setup

I'm looking to start creating proper isolated environments for django web apps. My first inclination is to use Docker. Also, it's usually recommended to use virtualenv with any python project to isolate dependencies.
Is virtualenv still necessary if I'm isolating projects via Docker images?
If your Docker container is relatively long-lived or your project dependencies change, there is still value in using a Python virtual-environment. Beyond (relatively) isolating dependencies of a codebase from other projects and the underlying system (and notably, the project at a given state), it allows for a certain measure of denoting the state of requirements at a given time.
For example, say that you make a Docker image for your Django app today, and end up using it for the following three weeks. Do you see your requirements.txt file being modified between now and then? Can you imagine a scenario in which you put out a hotpatch that comes with environmental changes?
As of Python 3.3, virtual-env is stdlib, which means it's very cheap to use, so I'd continue using it, just in case the Docker container isn't as disposable as you originally planned. Stated another way, even if your Docker-image pipeline is quite mature and the version of Python and dependencies are "pre-baked", it's such low-hanging fruit that while not explicitly necessary, it's worth sticking with best-practices.
No not really if each Python / Django is going to live in it's own container.

Moving from Docker Containers to Cloud Foundry containers

Recently I started to practice Dockers. Basically, I am running a C application on Docker container. Now, I want to try cloud foundry, therefore, trying to understand the difference between the two.
I'll describe the application as a novice because I am.
The application I start as a service(from /etc/init.d) and it reads a config file during startup, which specifies what all modules to load and IP of other services and it's own (0.0.0.0 does not work, so I have to give actual IP).
I had to manually update the IP and some details in the config file when the container starts. So, I wrote a startup script which did all the changes when the container starts and then the service start command.
Now, moving on to Cloud Foundry, the first thing I was not able to find is 'How to deploy C application' then I found a C build pack and a binary build pack option. I still have to try those but what I am not able to understand how I can provide a startup script to a cloud foundry container or in brief how to achieve what I was doing with Dockers.
The last option I have is to use docker containers in Cloud foundry, but I want to understand if I can achieve what I described above.
I hope I was clear enough to explain my doubt.
Help appreciated.
An old question, but a lot has changed since this was posted:
Recently I started to practice Dockers. Basically, I am running a C application on Docker container. Now, I want to try cloud foundry, therefore, trying to understand the difference between the two.
...
The last option I have is to use docker containers in Cloud foundry, but I want to understand if I can achieve what I described above.
There's nothing wrong with using Docker containers on CF. If you've already got everything set up to run inside a Docker container, being able to run that on CF give you yet another place you can easily deploy your workload.
While these are pretty minor, there are a couple requirements for your Docker container, so it's worth checking those to make sure it's possible to run on CF.
https://docs.cloudfoundry.org/devguide/deploy-apps/push-docker.html#requirements
Anyways, I am not working on this now as CF is not suitable for the project. It's an SIP application and CF only accepts HTTP/S requests.
OK, the elephant in the room. This is no longer true. CF has support for TCP routes. These allow you to receive TCP traffic directly to your application. This means, it's no longer just HTTP/S apps that are suitable for running on CF.
Instructions to set up your CF environment with TCP routing: https://docs.cloudfoundry.org/adminguide/enabling-tcp-routing.html
Instructions to use TCP routes as a developer: https://docs.cloudfoundry.org/devguide/deploy-apps/routes-domains.html#create-route-with-port
Now, moving on to Cloud Foundry, the first thing I was not able to find is 'How to deploy C application' then I found a C build pack and a binary build pack option.
Picking a buildpack is an important step. The buildpack takes your app and prepares it to run on CF. A C buildpack might sound nice as it would take your source code, build and run it, but it's going to get tricky because your C app likely depends on libraries. Libraries that may or may not be installed.
If you're going to go this route, you'll probably need to use CF's multi-buildpack support. This lets you run multiple buildpacks. If you pair this with the Apt buildpack, you can install the packages that you need so that any required libraries are available for your app as it's compiled.
https://docs.cloudfoundry.org/buildpacks/use-multiple-buildpacks.html
https://github.com/cloudfoundry/apt-buildpack
Using the binary buildpack is another option. In this case, you'd build your app locally. Perhaps in a docker container or on an Ubuntu VM (it needs to match the stack being used by your CF provider, i.e. cf stacks, currently Ubuntu Trusty or Ubuntu Bionic). Once you have a binary or binary + set of libraries, you can simply cf push the compiled artifacts. The binary buildpack will "run" (it actually does nothing) and then your app will be started with the command you specify.
My $0.02 only, but the binary buildpack is probably the easier of the two options.
what I am not able to understand how I can provide a startup script to a cloud foundry container or in brief how to achieve what I was doing with Dockers.
There's a few ways you can do this. The first is to specify a custom start command. You do this with cf push -c 'command'. This would normally be used to just start your app, like './my-app', but you could also use this to do other things.
Ex: cf push -c './prep-my-app.sh && ./my-app'
Or even just call your start script:
Ex: cf push -c './start-my-app.sh'.
CF also has support for a .profile script. This can be pushed with your app (at the root of the files you push), and it will be executed by the platform prior to your application starting up.
https://docs.cloudfoundry.org/devguide/deploy-apps/deploy-app.html#profile
Normally, you'd want to use a .profile script as you'd want to let the buildpack decide how to start your app (setting -c will override the buildpack), but in your case with the C or binary buildpack's, it's unlikely the buildpack will be able to do that, so you'll end up having to set a custom start command anyway.
For this specific case, I'd suggest using cf push -c as it's slightly easier, but for all other cases and apps deployed with other buildpacks, I'd suggest a .profile script.
Hope that helps!

Resources