I want zero downtime deploys on CloudBees - but my app needs to warm up - cloudbees

I want to do zero downtime deployment of apps on cloudbees (I am using continuous deployment) - but my app needs time to warm up?
Also, I would like to quickly be able to roll back if things go horribly wrong, is there a way to do this?

What you want, but may not realise it - is blue-green deployment, where you always have a active/standby app pair - and always deploy to the standby, cut over when ready.
See here for a better description.
Well, good news - there is a plugin for this here.
You can even automate this as part of your Jenkins build, for example, do something like this in your freestyle job script (this assumes you have setup an app as per the above link:
# INSTALL AND CONFIGURE BEES SDK
export BEES_HOME=/opt/cloudbees/cloudbees-sdk/
export PATH=$PATH:$BEES_HOME
if [ ! -d ~/.bees ]; then
bees init -f -a <account name> -ep us -k $BEES_API -s $BEES_SECRET
fi
bees plugin:install com.cloudbees.sdk.plugins:bg-plugin
# DEPLOY
bees app:bg:deploy -n <your app name> target/web-webapp.war
# WARM NEW SERVERS - for example - could be a smoke test here:
echo "Preparing new servers for router switch over..."
for i in {1..50}
do
curl -s "http://yourwebsite.com/" > /dev/null
sleep 5
done
# SWITCH ROUTER
echo "Switching router over to new servers..."
bees app:bg:switch -n <your app name> -f
# SHUTDOWN OLD SERVERS
echo "Shutting down old servers..."
bees app:bg:stop -n int -f

Related

Kubernetes rolling update with updating value in deployment file

I wanted to share a solution I did with kubernetes and have your opinion on best practice to do in such case. I'm still new to kubernetes.
I had a problem I wanted to be able to update my application by restarting my deployment pod that execute all the necessary action to do that already in command start.
I'm using microk8s and I wanted to just go to the good folder and execute microk8s kubectl apply -f myfilename and let kubernetes handle the rest with rolling update.
My issue was how to set dynamic value inside my .yaml file so the command would detect the change and start the process.
I've planned to do a bash script that do the job like the following:
file="my-file-deployment.yaml"
oldstr=`grep 'my' $file | xargs`
timestamp="$(date +"%Y-%m-%d-%H:%M:%S")"
newstr="value: my-version-$timestamp"
sed -i "s/$oldstr/$newstr/g" $file
echo "old version : $oldstr"
echo "Replaced String : $newstr"
sudo microk8s kubectl apply -f $file
on my deployment.yaml file I'm giving the following env:
env:
- name: version
value: my-version-2022-09-27-00:57:15
I'm switching with timestamp to a new value then I launch the command:
microk8s kubectl apply -f myfilename
it is working great for the moment. I still have to configure startupProbe to have a better rolling update execution because I'm having few second downtime which isn't cool.
Is there a better solution to work with rolling update using microk8s?
If you are trying to trigger a rolling update on your deployment (assuming it is a deployment), you can patch the deployment and let the cluster handle the rollout. Here's a trick I use and it's literally a one-liner:
kubectl -n {namespace} patch deployment {name-of-your-deployment} \
-p "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"date\":\"`date +'%s'`\"}}}}}"
This will patch your deployment, adding an annotation to the template block. In this way, the cluster thinks there is a change requiring an update to the deployment's pods, and will cycle them while following the rollingUpdate clause.
The date +'%s' will resolve to a different number each time so every time you run this, it will cause the cluster to cycle the deployment's pods.
We use this trick to force a rolling update when we have done an update that requires our pods to be restarted.
You can accompany this with the rollout status command to wait for the update to complete:
kubectl rollout status deployment/{name-of-your-deployment} -n {namespace}
So a complete line would be something like this if I wanted to rolling update my nginx deployment and wait for it to complete:
kubectl -n nginx patch deployment nginx \
-p "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"date\":\"`date +'%s'`\"}}}}}" \
&& kubectl rollout status deployment/nginx -n nginx
One caveat, though. Using kubectl patch does not make changes to the yamls on disk, so if you wanted a copy of the change recorded locally, such as for auditing purposes, similar to what you are doing at the moment, then you could adapt this to do it as a dry-run and redirect output to file:
kubectl -n nginx patch deployment nginx \
-p "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"date\":\"`date +'%s'`\"}}}}}" \
--dry-run=client \
-o yaml >patched-nginx.yaml

In Centos 7, how do you permanently consume messages with rabbitmq?

Good day,
I have just uploaded Symfony 3.4 project (PHP 7.2) to Centos server and my application needs to be connected to RabbitMQ. I want to do that in Centos server rabbitmq is constantly consuming messages. I know how to consume those messages temporarily by running this command:
bin/console rabbitmq:consumer messaging . But how could permanently I consume the messages on server? I tried to google but didn't find any useful information
In my application I've installed:
"php-amqplib/php-amqplib": "*",
"php-amqplib/rabbitmq-bundle": "*"
UPDATE:
I achieved my desired situation with the following command:
nohup bin/console rabbitmq:consumer <your-consumer> &
idk if there's an "official" way of doing it, but as with anything in Linux, you could just write a little daemon to do it, a minimum example would be to add this to your crontab -e
#reboot /bin/bash /project/folder/cronjob_starter.sh
with cronjob_starter.sh containing
#!/bin/bash
if [[ $(screen -ls | grep rabbitmq_daemon) ]]
then
echo "rabbitmq_daemon already running!"
/bin/true
else
# echo " rabbitmq_daemon not running!"
screen -S rabbitmq_daemon -dm
# workaround for https://savannah.gnu.org/bugs/index.php?54164
sleep 1
screen -S rabbitmq_daemon -X stuff "cd /project/folder; bin/console rabbitmq:consumer messaging^M"
fi
then you can inspect your daemon with screen -xS rabbitmq_daemon , or with the Screenie application (honestly idk how to "properly" install Screenie on CentOS, i just run curl https://gist.githubusercontent.com/divinity76/1a583968c997869b27a5ee2c1ed24259/raw/76453e61a92676386589fbb3f4ef0225ac98fb19/screenie.b64 | base64 -d | sudo tee /usr/local/bin/screenie ; sudo chmod 0555 /usr/local/bin/screenie; )
if there's an "official" way of doing it tho, you should probably do it the official way instead, i don't know anything about that unfortunately.

"Startup File" on Azure Docker Web App

Is the "Startup File" option on the docker web app options for docker-compose files? or shell commands? I cannot find any documentation for it...
Basically I'd like my Web App to run a docker-compose.yml instead of executing docker run [options] when I push an image to it.
This is documented now, see below or click here.
What are the expected values for the Startup File section when I
configure the runtime stack?
For Node.js, you specify the PM2 configuration file or your script
file. For .NET Core, specify your compiled DLL name as dotnet <myapp>.dll. For Ruby, you can specify the Ruby script that you want
to initialize your app with.
Not sure if this is still a problem but I just noticed it appends whatever you put in there to the default startup command.
2019-09-02 05:03:04.493 INFO - docker run -d -p 55721:80 --name xxxxxx -e WEBSITES_ENABLE_APP_SERVICE_STORAGE=false -e WEBSITE_SITE_NAME=xxxxx -e WEBSITE_AUTH_ENABLED=False -e PORT=80 -e WEBSITE_ROLE_INSTANCE_ID=0 -e WEBSITE_HOSTNAME=xxxxxx.azurewebsites.net -e WEBSITE_INSTANCE_ID=xxxxxxxxx -e HTTP_LOGGING_ENABLED=1 xxxxxx.azurecr.io/xxxxxxx:latest -p 80:4000 -p 443:8000
I put the -p 80:4000 -p 443:8000 into the textbox in the portal config
Azure Web Apps for Containers does not support multi-container apps (with docker-compose) at the time of writing.

How can I develop in docker container with intellij?

I know intellij has a docker container plugin, however it doesn't seem to allow me to develop inside the container itself. The idea is simple, I don't want to configure my host to have the correct environment tools. I'd rather just a docker container setup and then use intellij to find libs, functionality and such with in the container itself.
This would be incredibly helpful for c++, java, and scala dev. Also it would be useful debugging as well.
So is it possible to develop within a docker container with intellij?
So you just want to work within a container just as you would within a full-blown VM, right? Then you should just run a container, attach a display (to run IDEA) and start configuring your development environment.
For the display part I'd test some answers given in Can you run GUI apps in a docker container?. There are some very cool answers in this topic showing various approaches to running GUI apps within a container.
Shouldn't the approach be rather:
Have local repository and local IDE. In the repository have docker file and eventually docker-compose.yml, which spins up environment required to run project.
Mount your local drive with sources into docker (volumes), so changes done in your local folder are reflected in docker, similar in other direction.
Please look at this example for Intellij IDEA CI and JDK8 based on Alpine Linux (taken here
https://raw.githubusercontent.com/shaharv/docker/master/alpine/dev/Dockerfile)
# Alpine 3.8 C++/Java Developer Image
#
# For IntelliJ and GUI (X11), run the image with:
# $ XSOCK=/tmp/.X11-unix && sudo docker run -i -v $XSOCK:$XSOCK -e DISPLAY -u developer -t [image-name]
#
# Then run IntelliJ with:
# /idea-IC-191.6707.61/bin/idea.sh
FROM alpine:3.8
ENV LANG C.UTF-8
RUN set -ex && \
apk add --no-cache --update \
# basic packages
bash bash-completion coreutils file grep openssl openssh nano sudo tar xz \
# debug tools
gdb musl-dbg strace \
# docs and man
bash-doc man man-pages less less-doc \
# GUI fonts
font-noto \
# user utils
shadow
RUN set -ex && \
apk add --no-cache --update \
# C++ build tools
cmake g++ git linux-headers libpthread-stubs make
RUN set -ex && \
apk add --no-cache --update \
# Java tools
gradle openjdk8 openjdk8-dbg
# Install IntelliJ Community
RUN set -ex && \
wget https://download-cf.jetbrains.com/idea/ideaIC-2019.1.1-no-jbr.tar.gz && \
tar -xf ideaIC-2019.1.1-no-jbr.tar.gz && \
rm ideaIC-2019.1.1-no-jbr.tar.gz
# Create a new user with no password
ENV USERNAME developer
RUN set -ex && \
useradd --create-home --key MAIL_DIR=/dev/null --shell /bin/bash $USERNAME && \
passwd -d $USERNAME
# Set additional environment variables
ENV JAVA_HOME /usr/lib/jvm/java-1.8-openjdk
ENV JDK_HOME /usr/lib/jvm/java-1.8-openjdk
ENV JAVA_EXE /usr/lib/jvm/java-1.8-openjdk/bin/java
There is a better way to do this now with Jetbrains Gateway. Just make sure you have OpenSSH server installed (latest Ubuntu containers have this already installed) in the container that you initially ran with exposed ports, i.e. -p 220:22 (I like 220) and the SSH service running, i.e. service ssh start, after modifying the /etc/ssh/sshd_config to enable root login and password authentication then service ssh restart. Make sure you set a password for the root user, i.e. passwd root, (or go through other steps to setup a new user). Then all you need to do is open Jetbrains Gateway, and SSH to the container with the fields set thus: user=root, host=localhost, and port=220 (or whatever you chose); note, you will also need to specify a project location, which in my use case is a Java application repository root directory -- this means you will need to have Java and Maven or whatever other tools installed in the container at some point, but doesn't affect ability to connect. Assuming you connect with no issues you will see activity whereby Gateway installs an IDE backend inside the container (takes about 10 minutes) and then starts up a IDE client which is a light version of IntelliJ (or whatever other IDE version you selected) that is honestly a bit buggy at time of writing. But it works and has unblocked some of my colleagues stuck with Windows machines and not many options to upgrade to Macs in the current chip shortage environment. Note that any time you restart the container you also need to restart the SSH service unless you script it to automatically start up when the container does.

Reflecting code changes in docker containers

I have a basic hello world Node application written on express. I have just dockerised this application by creating a basic dockerfile in the applications root directory. I created a docker image, and then ran that image to run it in a running container
# Dockerfile
FROM node:0.10-onbuild
RUN npm install
EXPOSE 3000
CMD ["node", "./bin/www"]
sudo docker build -t docker-express
sudo docker run --name test-container -d -p 80:3000 docker-express
I can access the web application. My question is.. When I made code changes to my application, eg change 'hello world' to 'hello bob', my changes are not reflected within the running container.
What is a good development workflow to update changes in the container? Surely I shouldn't have to delete and rebuild the images after each change?
Thank you :)
Check out the section on Sharing Volumes. You should be able to share your host volume with the docker container and then any time you need a change you can just restart the server (or have something restart it for you!).
Your command would look something like: sudo docker run -v /src/webapp:/webapp --name test-container -d -p 80:3000 docker-express
Which mounts /src/webapp (on the host) to /webapp (in the container).