<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: bzinoun </title>
    <description>The latest articles on Forem by bzinoun  (@bzinoun).</description>
    <link>https://forem.com/bzinoun</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F172630%2F8c9df228-1eff-4eba-9667-7663813e74fa.jpg</url>
      <title>Forem: bzinoun </title>
      <link>https://forem.com/bzinoun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bzinoun"/>
    <language>en</language>
    <item>
      <title> [ 🇬🇧 ] Move from an IBM Cloud account to another </title>
      <dc:creator>bzinoun </dc:creator>
      <pubDate>Mon, 16 Dec 2019 09:43:41 +0000</pubDate>
      <link>https://forem.com/bzinoun/move-from-an-ibm-cloud-account-to-another-4kj0</link>
      <guid>https://forem.com/bzinoun/move-from-an-ibm-cloud-account-to-another-4kj0</guid>
      <description>&lt;p&gt;A few weeks ago, we had to move from an IBMCloud account to another , the cause was some enterprise constraints , you know the movie 🤷‍♂‍ .&lt;/p&gt;

&lt;p&gt;As IBMCloud doesn’t provide tools out of the box for it, our migration was based on our daily CI/CD pipeline! Wow 🤦‍♂‍&lt;/p&gt;

&lt;p&gt;Now, let's see what we need to move to the new Cloud:&lt;/p&gt;

&lt;p&gt;➡️ 30 CloudFoundry&lt;br&gt;
➡️ 10 PostgreSql&lt;br&gt;
➡️ 2 MongoDB&lt;br&gt;
➡️ 3 AppID (OPIDC)&lt;br&gt;
➡️ 4 domain names&lt;/p&gt;

&lt;p&gt;Okey 49 assets to move, seems good.&lt;/p&gt;

&lt;p&gt;Now we have seen the most asset we have, the idea is to use CI/CD pipelines for &lt;em&gt;most&lt;/em&gt; of our deployments.&lt;/p&gt;

&lt;p&gt;So, what's about our application’s pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Some applications are deployed with GitlabCI pipeline =&amp;gt; should be OK&lt;/li&gt;
&lt;li&gt;❌ Some applications are deployed with IBMCloud Devops pipeline =&amp;gt; which is not cloud agnostic &lt;/li&gt;
&lt;li&gt;❌ No Infrastructure as code for BDD, AppId ...etc. =&amp;gt; Hmm manually provisioning ?
&lt;/li&gt;
&lt;li&gt;✅ Data migration? all our assets have an API for import/export =&amp;gt; it's should be OK. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We have some bad and good thinks, moving all that stuff with a minimal down want be the best way , so without too much thinking &lt;/p&gt;

&lt;p&gt;💡 Blue Green deployment is the best way &lt;br&gt;
&lt;em&gt;More about blue green deployment from Martin Fowler  &lt;a href="https://martinfowler.com/bliki/BlueGreenDeployment.html"&gt;here&lt;/a&gt;&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/d3mlE7uhX8KFgEmY/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/d3mlE7uhX8KFgEmY/giphy.gif" alt="Dak'aa"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Gif below describe in visual way how we proceed: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X5tvU6py--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bwr1poqwae3xayog2xbn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X5tvU6py--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bwr1poqwae3xayog2xbn.gif" alt="migrationgif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The process can be splitted to 6 steps describes as below: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt; - unifying our deployment Pipeline by moving all our CI/CD pipeline to GitlabCI. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt; - Move all non-production assets . As we are working in an agile mode we move the dev environment first then, when needed, staging , sandbox&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt; - Move the production assets, then data migration, then push the provisional production URL to the Business analyst / Product Owner for a Go/No GO &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt; - Once we have the GO -&amp;gt; Migrate the domain name from the legacy cloud to the New IBMCloud &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt; - Remove the death pipeline code , and remove the old assets from legacy Cloud &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6&lt;/strong&gt; Celebrate with the Team. 🎊 🎉🎊 🎉&lt;/p&gt;

&lt;p&gt;So, without going too deep into details of every step , this how we do the work . &lt;/p&gt;




&lt;p&gt;In the end, it's been not easy, and having a devops culture helps a lot and i can resume what we have learn : &lt;/p&gt;

&lt;p&gt;1- &lt;strong&gt;we have to be cloud agnostic:&lt;/strong&gt; &lt;br&gt;
 A toolchain must be a cloud agnostic. If we want a change our &lt;br&gt;
  deployment strategy, it must me smooth.&lt;/p&gt;

&lt;p&gt;2 - &lt;strong&gt;Devops culture is a must&lt;/strong&gt;&lt;br&gt;
The pipeline source must be versioned, involved with the code source. &lt;strong&gt;The dev Team is the owner of the pipeline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;3 - &lt;strong&gt;Start Easy&lt;/strong&gt; &lt;br&gt;
  Dev environment first, as we work on agile , the other environments will be &lt;strong&gt;deployed in an iterative and incremental way&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;4 - &lt;strong&gt;If it’s hard manually, then script it .&lt;/strong&gt;&lt;br&gt;
  Special attention to the Data migration for every type of asset. ( AppId , SQL , NoSql , Cloud object Storage …etc ) &lt;/p&gt;

&lt;p&gt;That's all folks, and how will you do in the same situation ?&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>migration</category>
      <category>devops</category>
      <category>ibmcloud</category>
    </item>
    <item>
      <title> [ 🇬🇧 ] -IBMCloud- K8S ready CI/CD toolchain</title>
      <dc:creator>bzinoun </dc:creator>
      <pubDate>Sun, 09 Jun 2019 15:53:38 +0000</pubDate>
      <link>https://forem.com/bzinoun/ibmcloud-k8s-ready-ci-cd-toolchain-1n3f</link>
      <guid>https://forem.com/bzinoun/ibmcloud-k8s-ready-ci-cd-toolchain-1n3f</guid>
      <description>&lt;p&gt;As i am an Ibmcloud (Bluemix)user, i share with you a ready Devops toolchain that i use for my Kubernetes Deployment .&lt;/p&gt;




&lt;p&gt;In the interest of efficiency and continuous deployment, the implementation of a ToolChain of continuous deployment remains a must. The latter is divided into 3 Steps :&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Validate docker file&lt;/li&gt;
&lt;li&gt;Build Docker image&lt;/li&gt;
&lt;li&gt;Push docker images to Registry&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step2 : Non blocking Step
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Vulnerability scanning for the docker image&lt;/li&gt;
&lt;li&gt;Get the recommendations to fix them&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step3
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;validate deployment files&lt;/li&gt;
&lt;li&gt;deploy changes to Kubernetes Cluster&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🛠 Toolchain
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tS9bFITX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jkgjvggy4xwpeyg1ch9f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tS9bFITX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jkgjvggy4xwpeyg1ch9f.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 : Build
&lt;/h2&gt;

&lt;p&gt;This step is responsible to verify docker file with a linter then build the image and push it to registry . &lt;br&gt;
Bellow we describe the shell scripte that do the stuff : &lt;/p&gt;

&lt;h3&gt;
  
  
  Verify Docker file
&lt;/h3&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
echo "REGISTRY_URL=${REGISTRY_URL}"
echo "REGISTRY_NAMESPACE=${REGISTRY_NAMESPACE}"
echo "IMAGE_NAME=${IMAGE_NAME}"
echo "ARCHIVE_DIR=${ARCHIVE_DIR}"
echo "DOCKER_ROOT=${DOCKER_ROOT}"
echo "DOCKER_FILE=${DOCKER_FILE}"

# View build properties
if [ -f build.properties ]; then 
  echo "build.properties:"
  cat build.properties
else 
  echo "build.properties : not found"
fi 

echo "=========================================================="
echo "Checking for Dockerfile at the repository root"
if [ -z "${DOCKER_ROOT}" ]; then DOCKER_ROOT=. ; fi
if [ -z "${DOCKER_FILE}" ]; then DOCKER_FILE=Dockerfile ; fi
if [ -f ${DOCKER_ROOT}/${DOCKER_FILE} ]; then 
echo -e "Dockerfile found at: ${DOCKER_FILE}"
else
    echo "Dockerfile not found at: ${DOCKER_FILE}"
    exit 1
fi
echo "Linting Dockerfile"
npm install -g dockerlint
dockerlint -f ${DOCKER_ROOT}/${DOCKER_FILE}

echo "=========================================================="
echo "Checking registry current plan and quota"
bx cr plan
bx cr quota
echo "If needed, discard older images using: bx cr image-rm"
echo "Checking registry namespace: ${REGISTRY_NAMESPACE}"
NS=$( bx cr namespaces | grep ${REGISTRY_NAMESPACE} ||: )
if [ -z "${NS}" ]; then
    echo "Registry namespace ${REGISTRY_NAMESPACE} not found, creating it."
    bx cr namespace-add ${REGISTRY_NAMESPACE}
    echo "Registry namespace ${REGISTRY_NAMESPACE} created."
else 
    echo "Registry namespace ${REGISTRY_NAMESPACE} found."
fi
echo -e "Existing images in registry"
bx cr images --restrict ${REGISTRY_NAMESPACE}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Build Docker Image
&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
echo "REGISTRY_URL=${REGISTRY_URL}"
echo "REGISTRY_NAMESPACE=${REGISTRY_NAMESPACE}"
echo "IMAGE_NAME=${IMAGE_NAME}"
echo "BUILD_NUMBER=${BUILD_NUMBER}"
echo "ARCHIVE_DIR=${ARCHIVE_DIR}"
echo "GIT_BRANCH=${GIT_BRANCH}"
echo "GIT_COMMIT=${GIT_COMMIT}"
echo "DOCKER_ROOT=${DOCKER_ROOT}"
echo "DOCKER_FILE=${DOCKER_FILE}"

# View build properties
if [ -f build.properties ]; then 
  echo "build.properties:"
  cat build.properties
else 
  echo "build.properties : not found"
fi 

# To review or change build options use:
echo -e "build --help"

 bx cr build --help

echo -e "Existing images in registry"
bx cr images

# Minting image tag using format: BUILD_NUMBER--BRANCH-COMMIT_ID-TIMESTAMP
# e.g. 3-master-50da6912-20181123114435
# (use build number as first segment to allow image tag as a patch release name according to semantic versioning)

TIMESTAMP=$( date -u "+%Y%m%d%H%M%S")
IMAGE_TAG=${TIMESTAMP}
if [ ! -z "${GIT_COMMIT}" ]; then
  GIT_COMMIT_SHORT=$( echo ${GIT_COMMIT} | head -c 8 ) 
  IMAGE_TAG=${GIT_COMMIT_SHORT}-${IMAGE_TAG}
fi
if [ ! -z "${GIT_BRANCH}" ]; then IMAGE_TAG=${GIT_BRANCH}-${IMAGE_TAG} ; fi
IMAGE_TAG=${BUILD_NUMBER}-${IMAGE_TAG}
echo "=========================================================="
echo -e "BUILDING CONTAINER IMAGE: ${IMAGE_NAME}:${IMAGE_TAG}"
if [ -z "${DOCKER_ROOT}" ]; then DOCKER_ROOT=. ; fi
if [ -z "${DOCKER_FILE}" ]; then DOCKER_FILE=${DOCKER_ROOT}/Dockerfile ; fi


#set -x
#bx cr build -t ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/${IMAGE_NAME}:${IMAGE_TAG} ${DOCKER_ROOT} -f ${DOCKER_FILE}
#set +x

bx cr build -t ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/${IMAGE_NAME}:${TIMESTAMP} ${DOCKER_ROOT} -f ${DOCKER_FILE}


bx cr image-inspect ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/${IMAGE_NAME}:${TIMESTAMP} 

# Set PIPELINE_IMAGE_URL for subsequent jobs in stage (e.g. Vulnerability Advisor)
export PIPELINE_IMAGE_URL="$REGISTRY_URL/$REGISTRY_NAMESPACE/$IMAGE_NAME:$IMAGE_TAG"

bx cr images --restrict ${REGISTRY_NAMESPACE}/${IMAGE_NAME}

echo "=========================================================="
echo "COPYING ARTIFACTS needed for deployment and testing (in particular build.properties)"

echo "Checking archive dir presence"
if [ -z "${ARCHIVE_DIR}" ]; then
  echo -e "Build archive directory contains entire working directory."
else
  echo -e "Copying working dir into build archive directory: ${ARCHIVE_DIR} "
  mkdir -p ${ARCHIVE_DIR}
  find . -mindepth 1 -maxdepth 1 -not -path "./$ARCHIVE_DIR" -exec cp -R '{}' "${ARCHIVE_DIR}/" ';'
fi

# If already defined build.properties from prior build job, append to it.
cp build.properties $ARCHIVE_DIR/ || :

# IMAGE information from build.properties is used in Helm Chart deployment to set the release name
echo "IMAGE_NAME=${IMAGE_NAME}" &amp;gt;&amp;gt; $ARCHIVE_DIR/build.properties
echo "IMAGE_TAG=${IMAGE_TAG}" &amp;gt;&amp;gt; $ARCHIVE_DIR/build.properties
# REGISTRY information from build.properties is used in Helm Chart deployment to generate cluster secret
echo "REGISTRY_URL=${REGISTRY_URL}" &amp;gt;&amp;gt; $ARCHIVE_DIR/build.properties
echo "REGISTRY_NAMESPACE=${REGISTRY_NAMESPACE}" &amp;gt;&amp;gt; $ARCHIVE_DIR/build.properties
echo "GIT_BRANCH=${GIT_BRANCH}" &amp;gt;&amp;gt; $ARCHIVE_DIR/build.properties
echo "TIMESTAMP=${TIMESTAMP}" &amp;gt;&amp;gt; $ARCHIVE_DIR/build.properties

echo "File 'build.properties' created for passing env variables to subsequent pipeline jobs:"
cat $ARCHIVE_DIR/build.properties
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Step 2 : Validate
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Security Check
&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
# uncomment to debug the script
#set -x

# View build properties
if [ -f build.properties ]; then 
  echo "build.properties:"
  cat build.properties
else 
  echo "build.properties : not found"
fi 

PIPELINE_IMAGE_URL=${REGISTRY_URL}/${REGISTRY_NAMESPACE}/${IMAGE_NAME}:${TIMESTAMP}

echo "PIPELINE_IMAGE_URL=${PIPELINE_IMAGE_URL}"
echo "REGISTRY_URL=${REGISTRY_URL}"
echo "REGISTRY_NAMESPACE=${REGISTRY_NAMESPACE}"
echo "IMAGE_NAME=${IMAGE_NAME}"
echo "IMAGE_TAG=${IMAGE_TAG}"
echo "TIMESTAMP=${TIMESTAMP}"

bx cr images --restrict ${REGISTRY_NAMESPACE}/${IMAGE_NAME}
echo -e "Checking vulnerabilities in image: ${PIPELINE_IMAGE_URL}"

for ITER in {1..30}
do
  set +e
  STATUS=$( bx cr va -e -o json ${PIPELINE_IMAGE_URL} | jq -r '.[0].status' )
  set -e
  # Possible status from Vulnerability Advisor: OK, UNSUPPORTED, INCOMPLETE, UNSCANNED, FAIL, WARN
  if [[ ${STATUS} != "INCOMPLETE" &amp;amp;&amp;amp; ${STATUS} != "UNSCANNED" ]]; then
    break
  fi
  echo -e "${ITER} STATUS ${STATUS} : A vulnerability report was not found for the specified image."
  echo "Either the image doesn't exist or the scan hasn't completed yet. "
  echo "Waiting for scan to complete..."
  sleep 10
done
set +e
bx cr va -e ${PIPELINE_IMAGE_URL}
set -e
STATUS=$( bx cr va -e -o json ${PIPELINE_IMAGE_URL} | jq -r '.[0].status' )
[[ ${STATUS} == "OK" ]] || [[ ${STATUS} == "UNSUPPORTED" ]] || [[ ${STATUS} == "WARN" ]] || { echo "ERROR: The vulnerability scan was not successful, check the OUTPUT of the command and try again."; exit 1; }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Step 3 : Deploy
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Verify K8S deployments file
&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
# uncomment to debug the script
#set -x
echo "IMAGE_NAME=${IMAGE_NAME}"
echo "IMAGE_TAG=${IMAGE_TAG}"
echo "REGISTRY_URL=${REGISTRY_URL}"
echo "REGISTRY_NAMESPACE=${REGISTRY_NAMESPACE}"
echo "DEPLOYMENT_FILE=${DEPLOYMENT_FILE}"

# Fix : after getting error with IMAGE_TAG variable
IMAGE_TAG=${TIMESTAMP}


# Input env variables from pipeline job
echo "PIPELINE_KUBERNETES_CLUSTER_NAME=${PIPELINE_KUBERNETES_CLUSTER_NAME}"
if [ -z "${CLUSTER_NAMESPACE}" ]; then CLUSTER_NAMESPACE=default ; fi
echo "CLUSTER_NAMESPACE=${CLUSTER_NAMESPACE}"

echo "=========================================================="
echo "DEPLOYING using manifest"
echo -e "Updating ${DEPLOYMENT_FILE} with image name: ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/${IMAGE_NAME}:${IMAGE_TAG}"
if [ -z "${DEPLOYMENT_FILE}" ]; then DEPLOYMENT_FILE=deployment.yml ; fi
if [ -f ${DEPLOYMENT_FILE} ]; then
    sed -i "s~^\([[:blank:]]*\)image:.*$~\1image: ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/${IMAGE_NAME}:${IMAGE_TAG}~" ${DEPLOYMENT_FILE}
    cat ${DEPLOYMENT_FILE}
else 
    echo -e "${red}Kubernetes deployment file '${DEPLOYMENT_FILE}' not found${no_color}"
    exit 1
fi    
set -x
kubectl apply --namespace ${CLUSTER_NAMESPACE} -f ${DEPLOYMENT_FILE} 
set +x

echo ""
echo "=========================================================="
IMAGE_REPOSITORY=${REGISTRY_URL}/${REGISTRY_NAMESPACE}/${IMAGE_NAME}
echo -e "CHECKING deployment status of ${IMAGE_REPOSITORY}:${IMAGE_TAG}"
echo ""
for ITERATION in {1..30}
do
  DATA=$( kubectl get pods --namespace ${CLUSTER_NAMESPACE} -o json )
  NOT_READY=$( echo $DATA | jq '.items[].status | select(.containerStatuses!=null) | .containerStatuses[] | select(.image=="'"${IMAGE_REPOSITORY}:${IMAGE_TAG}"'") | select(.ready==false) ' )
  if [[ -z "$NOT_READY" ]]; then
    echo -e "All pods are ready:"
    echo $DATA | jq '.items[].status | select(.containerStatuses!=null) | .containerStatuses[] | select(.image=="'"${IMAGE_REPOSITORY}:${IMAGE_TAG}"'") | select(.ready==true) '
    break # deployment succeeded
  fi
  REASON=$(echo $DATA | jq '.items[].status | select(.containerStatuses!=null) | .containerStatuses[] | select(.image=="'"${IMAGE_REPOSITORY}:${IMAGE_TAG}"'") | .state.waiting.reason')
  echo -e "${ITERATION} : Deployment still pending..."
  echo -e "NOT_READY:${NOT_READY}"
  echo -e "REASON: ${REASON}"
  if [[ ${REASON} == *ErrImagePull* ]] || [[ ${REASON} == *ImagePullBackOff* ]]; then
    echo "Detected ErrImagePull or ImagePullBackOff failure. "
    echo "Please check proper authenticating to from cluster to image registry (e.g. image pull secret)"
    break; # no need to wait longer, error is fatal
  elif [[ ${REASON} == *CrashLoopBackOff* ]]; then
    echo "Detected CrashLoopBackOff failure. "
    echo "Application is unable to start, check the application startup logs"
    break; # no need to wait longer, error is fatal
  fi
  sleep 5
done

APP_NAME=$(kubectl get pods --namespace ${CLUSTER_NAMESPACE} -o json | jq -r '.items[].status | select(.containerStatuses!=null) | .containerStatuses[] | select(.image=="'"${IMAGE_REPOSITORY}:${IMAGE_TAG}"'") | .name' | head -n 1)
echo -e "APP: ${APP_NAME}"
echo "DEPLOYED PODS:"
kubectl describe pods --selector app=${APP_NAME} --namespace ${CLUSTER_NAMESPACE}
if [ ! -z "${APP_NAME}" ]; then
  APP_SERVICE=$(kubectl get services --namespace ${CLUSTER_NAMESPACE} -o json | jq -r ' .items[] | select (.spec.selector.app=="'"${APP_NAME}"'") | .metadata.name ')
  echo -e "SERVICE: ${APP_SERVICE}"
  echo "DEPLOYED SERVICES:"
  kubectl describe services ${APP_SERVICE} --namespace ${CLUSTER_NAMESPACE}
fi
#echo "Application Logs"
#kubectl logs --selector app=${APP_NAME} --namespace ${CLUSTER_NAMESPACE}  
echo ""
if [[ ! -z "$NOT_READY" ]]; then
  echo ""
  echo "=========================================================="
  echo "DEPLOYMENT FAILED"
  exit 1
fi

echo ""
echo "=========================================================="
echo "DEPLOYMENT SUCCEEDED"
if [ ! -z "${APP_SERVICE}" ]; then
  echo ""
  IP_ADDR=$(bx cs workers ${PIPELINE_KUBERNETES_CLUSTER_NAME} | grep normal | head -n 1 | awk '{ print $2 }')
  PORT=$( kubectl get services --namespace ${CLUSTER_NAMESPACE} | grep ${APP_SERVICE} | sed 's/.*:\([0-9]*\).*/\1/g' )
  echo ""
  echo -e "VIEW THE APPLICATION AT: http://${IP_ADDR}:${PORT}"
fi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Deploy to K8S
&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
# uncomment to debug the script
#set -x

echo "IMAGE_NAME=${IMAGE_NAME}"
echo "IMAGE_TAG=${IMAGE_TAG}"
echo "REGISTRY_URL=${REGISTRY_URL}"
echo "REGISTRY_NAMESPACE=${REGISTRY_NAMESPACE}"
echo "DEPLOYMENT_FILE=${DEPLOYMENT_FILE}"

IMAGE_TAG=${TIMESTAMP}

# Input env variables from pipeline job
echo "PIPELINE_KUBERNETES_CLUSTER_NAME=${PIPELINE_KUBERNETES_CLUSTER_NAME}"
if [ -z "${CLUSTER_NAMESPACE}" ]; then CLUSTER_NAMESPACE=default ; fi
echo "CLUSTER_NAMESPACE=${CLUSTER_NAMESPACE}"

echo "=========================================================="
echo "DEPLOYING using manifest"
echo -e "Updating ${DEPLOYMENT_FILE} with image name: ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/${IMAGE_NAME}:${IMAGE_TAG}"
if [ -z "${DEPLOYMENT_FILE}" ]; then DEPLOYMENT_FILE=deployment.yml ; fi
if [ -f ${DEPLOYMENT_FILE} ]; then
    sed -i "s~^\([[:blank:]]*\)image:.*$~\1image: ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/${IMAGE_NAME}:${IMAGE_TAG}~" ${DEPLOYMENT_FILE}
    cat ${DEPLOYMENT_FILE}
else 
    echo -e "${red}Kubernetes deployment file '${DEPLOYMENT_FILE}' not found${no_color}"
    exit 1
fi    
set -x
kubectl apply --namespace ${CLUSTER_NAMESPACE} -f ${DEPLOYMENT_FILE} 
set +x

echo ""
echo "=========================================================="
IMAGE_REPOSITORY=${REGISTRY_URL}/${REGISTRY_NAMESPACE}/${IMAGE_NAME}
echo -e "CHECKING deployment status of ${IMAGE_REPOSITORY}:${IMAGE_TAG}"
echo ""
for ITERATION in {1..30}
do
  DATA=$( kubectl get pods --namespace ${CLUSTER_NAMESPACE} -o json )
  NOT_READY=$( echo $DATA | jq '.items[].status | select(.containerStatuses!=null) | .containerStatuses[] | select(.image=="'"${IMAGE_REPOSITORY}:${IMAGE_TAG}"'") | select(.ready==false) ' )
  if [[ -z "$NOT_READY" ]]; then
    echo -e "All pods are ready:"
    echo $DATA | jq '.items[].status | select(.containerStatuses!=null) | .containerStatuses[] | select(.image=="'"${IMAGE_REPOSITORY}:${IMAGE_TAG}"'") | select(.ready==true) '
    break # deployment succeeded
  fi
  REASON=$(echo $DATA | jq '.items[].status | select(.containerStatuses!=null) | .containerStatuses[] | select(.image=="'"${IMAGE_REPOSITORY}:${IMAGE_TAG}"'") | .state.waiting.reason')
  echo -e "${ITERATION} : Deployment still pending..."
  echo -e "NOT_READY:${NOT_READY}"
  echo -e "REASON: ${REASON}"
  if [[ ${REASON} == *ErrImagePull* ]] || [[ ${REASON} == *ImagePullBackOff* ]]; then
    echo "Detected ErrImagePull or ImagePullBackOff failure. "
    echo "Please check proper authenticating to from cluster to image registry (e.g. image pull secret)"
    break; # no need to wait longer, error is fatal
  elif [[ ${REASON} == *CrashLoopBackOff* ]]; then
    echo "Detected CrashLoopBackOff failure. "
    echo "Application is unable to start, check the application startup logs"
    break; # no need to wait longer, error is fatal
  fi
  sleep 5
done

APP_NAME=$(kubectl get pods --namespace ${CLUSTER_NAMESPACE} -o json | jq -r '.items[].status | select(.containerStatuses!=null) | .containerStatuses[] | select(.image=="'"${IMAGE_REPOSITORY}:${IMAGE_TAG}"'") | .name' | head -n 1)
echo -e "APP: ${APP_NAME}"
echo "DEPLOYED PODS:"
kubectl describe pods --selector app=${APP_NAME} --namespace ${CLUSTER_NAMESPACE}
if [ ! -z "${APP_NAME}" ]; then
  APP_SERVICE=$(kubectl get services --namespace ${CLUSTER_NAMESPACE} -o json | jq -r ' .items[] | select (.spec.selector.app=="'"${APP_NAME}"'") | .metadata.name ')
  echo -e "SERVICE: ${APP_SERVICE}"
  echo "DEPLOYED SERVICES:"
  kubectl describe services ${APP_SERVICE} --namespace ${CLUSTER_NAMESPACE}
fi
#echo "Application Logs"
#kubectl logs --selector app=${APP_NAME} --namespace ${CLUSTER_NAMESPACE}  
echo ""
if [[ ! -z "$NOT_READY" ]]; then
  echo ""
  echo "=========================================================="
  echo "DEPLOYMENT FAILED"
  exit 1
fi

echo ""
echo "=========================================================="
echo "DEPLOYMENT SUCCEEDED"
if [ ! -z "${APP_SERVICE}" ]; then
  echo ""
  IP_ADDR=$(bx cs workers ${PIPELINE_KUBERNETES_CLUSTER_NAME} | grep normal | head -n 1 | awk '{ print $2 }')
  PORT=$( kubectl get services --namespace ${CLUSTER_NAMESPACE} | grep ${APP_SERVICE} | sed 's/.*:\([0-9]*\).*/\1/g' )
  echo ""
  echo -e "VIEW THE APPLICATION AT: http://${IP_ADDR}:${PORT}"
fi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;
  
  
  Problems
&lt;/h1&gt;
&lt;h3&gt;
  
  
  ⚠ Cluster kube always on "Pending"
&lt;/h3&gt;

&lt;p&gt;After creating k8s cluster , the latter is still always in 'Pending' status&lt;/p&gt;

&lt;p&gt;✅ Resolution : Update Kubernetes cluster to last proposed version &lt;/p&gt;

&lt;p&gt;⚠ Can't publish docker image on registry&lt;/p&gt;

&lt;p&gt;On the BUILD step of the Toolchain FAILED , because of the name of the image &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The supplied image name was invalid.
Correct the image name, and try again.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;✅  add a TIMESTAMP to docker image name . Replace the ${TAG_NAME} with ${TIMESTAMP}&lt;/p&gt;




&lt;p&gt;That's all , thank you for reading and your feedback is highly appreciated &lt;/p&gt;

</description>
      <category>ibmcloud</category>
      <category>kubernetes</category>
      <category>showdev</category>
      <category>devops</category>
    </item>
    <item>
      <title> [ 🇬🇧 ] What Kubernetes is and what it is not</title>
      <dc:creator>bzinoun </dc:creator>
      <pubDate>Wed, 05 Jun 2019 23:28:12 +0000</pubDate>
      <link>https://forem.com/bzinoun/what-kubernetes-is-and-what-it-is-not-1kkd</link>
      <guid>https://forem.com/bzinoun/what-kubernetes-is-and-what-it-is-not-1kkd</guid>
      <description>&lt;p&gt;Two questions were very important to me when my interest was on Kubernetes : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is Kubernetes ?&lt;/li&gt;
&lt;li&gt;What Kubernetes is not  ?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By answering to these two questions, i was sure to start from the right point and also know the responsibility of Kubernetes . &lt;/p&gt;

&lt;p&gt;So let's make a pragmatic responses about that . &lt;/p&gt;

&lt;h3&gt;
  
  
  💡What is Kubernetes ?
&lt;/h3&gt;

&lt;p&gt;Kubernetes is a platform that wrap a huge number of services and capabilities ; these latter is growing day after day . &lt;br&gt;
From a top level we can say , the core functionalities of Kubernetes  is it's ability to manage containers across linux based infrastructure . &lt;br&gt;
But Kubernetes brings also a lot of feature such as : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Managing Secrets&lt;/li&gt;
&lt;li&gt;Checking applications Health&lt;/li&gt;
&lt;li&gt;Scaling application : Scale app and down&lt;/li&gt;
&lt;li&gt;Auto Scaling&lt;/li&gt;
&lt;li&gt;Instance replication&lt;/li&gt;
&lt;li&gt;Discovering resource&lt;/li&gt;
&lt;li&gt;Naming Resource&lt;/li&gt;
&lt;li&gt;Monitoring resource&lt;/li&gt;
&lt;li&gt;Managing and mounting Storage system&lt;/li&gt;
&lt;li&gt;Providing security component : Authorization , Authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In one sentence the responsibility of K8S is &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Platform for managing containerized workloads and services, that facilitates both declarative configuration and automation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ⛔️ What Kubenetes is not ?
&lt;/h3&gt;

&lt;p&gt;The Common mistake is to say  &lt;em&gt;Kubernetes is a Paas&lt;/em&gt; ! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kubernetes is not a platform as a service&lt;/strong&gt; (Paas) , in my opinion  Rancher is a Paas for Kubernetes  , It provide a high level configuration for kubernetes and provide some default configuration for Kubernetes to . &lt;/p&gt;

&lt;p&gt;In fact  Kubernetes doesn't dictate many aspects of our system and leaves them up to us to manage them . &lt;/p&gt;

&lt;p&gt;In facts Kubernetes does  : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;not require a specific application type or a dependency framework&lt;/li&gt;
&lt;li&gt;not require a specific programming language&lt;/li&gt;
&lt;li&gt;not provide any database&lt;/li&gt;
&lt;li&gt;not provide any message queues&lt;/li&gt;
&lt;li&gt;allow us to choose our logging system&lt;/li&gt;
&lt;li&gt;allow us to choose our monitoring  &amp;amp; alerting system&lt;/li&gt;
&lt;li&gt;..etc&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  That's all Folks
&lt;/h3&gt;




&lt;p&gt;In the next post we will discuss the relation between K8S and containers . We will find response for questions such as : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's benefits of containers&lt;/li&gt;
&lt;li&gt;How we need to manage our containers&lt;/li&gt;
&lt;li&gt;...etc&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>discuss</category>
      <category>docker</category>
    </item>
    <item>
      <title> [ 🇬🇧 ] IBM AppId integration with Springboot 2 </title>
      <dc:creator>bzinoun </dc:creator>
      <pubDate>Tue, 28 May 2019 17:16:50 +0000</pubDate>
      <link>https://forem.com/bzinoun/ibm-appid-integration-with-springboot-2-37o7</link>
      <guid>https://forem.com/bzinoun/ibm-appid-integration-with-springboot-2-37o7</guid>
      <description>&lt;h4&gt;
  
  
  What we gonna do
&lt;/h4&gt;

&lt;p&gt;through this article we will focus on how to integrate the OpenId Connect Server, AppID, proposed by IBM Cloud with a Java application under Springboot.&lt;/p&gt;

&lt;h4&gt;
  
  
  Prerequisites
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;An IBM Cloud Account: The free version is sufficient&lt;/li&gt;
&lt;li&gt;Knowledge about OAuth2 flow&lt;/li&gt;
&lt;li&gt;Knowledge knowledge of the Java ecosystem - Springboot.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  IBM AppId in few lines
&lt;/h4&gt;

&lt;p&gt;App ID is the OpenId Connect service from IbmCloud . It helps developers to easily add authentication to their web or mobile apps with few lines of code, and it helps them secure their cloud-native applications and services on IBM Cloud. AppID propose a connection trought Facebook Google etc ... &lt;/p&gt;

&lt;p&gt;App ID also helps manage user-specific data that developers can use to build personalized app experiences.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;/!\  We assume that you know how to create a basic Java Spring Boot App &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Okay , let's show some code !&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Configure AppId with Spring Boot
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Add the dependencies to pom.xml
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;       &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-security&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- spring-security-oauth2-autoconfigure tells the framework to use OAuth2, instead of basic http security --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.security.oauth.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-security-oauth2-autoconfigure&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.0.0.RELEASE&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create a ResourceSecurityConfiguration Java class to enable OAuth2, and Rest capabilities. Also, extend from ResourceServerConfigurerAdapter class, to later configure security access.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@EnableResourceServer&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ResourceSecurityConfiguration&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ResourceServerConfigurerAdapter&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Override security configuration by adding a configure method.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@EnableResourceServer&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ResourceSecurityConfiguration&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ResourceServerConfigurerAdapter&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpSecurity&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authorizeRequests&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;antMatchers&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api**"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/user"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/userInfo"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;authenticated&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;logout&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;logoutSuccessUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;permitAll&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;csrf&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;disable&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add two endpoints to the ResourceSecurityConfiguration Java class that will be accessible when you perform GET Calls from the front end. The /user endpoint gives us the logged-in user object (principal) and the /userInfo endpoint returns a string with the details.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@EnableResourceServer&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ResourceSecurityConfiguration&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ResourceServerConfigurerAdapter&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpSecurity&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authorizeRequests&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;antMatchers&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api**"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/user"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/userInfo"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;authenticated&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;logout&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;logoutSuccessUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;permitAll&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;csrf&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;disable&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// for open id&lt;/span&gt;
    &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/user"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Principal&lt;/span&gt; &lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Principal&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//Principal holds the logged in user information.&lt;/span&gt;
        &lt;span class="c1"&gt;// Spring automatically populates this principal object after login.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// for open id&lt;/span&gt;
    &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/userInfo"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;userInfo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Principal&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;OAuth2Authentication&lt;/span&gt; &lt;span class="n"&gt;oAuth2Authentication&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OAuth2Authentication&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="n"&gt;authentication&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oAuth2Authentication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserAuthentication&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;//Manually getting the details from the authentication, and returning them as String.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;authentication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDetails&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add necessary AppId config values from information that you'll get from your service credentials / IBM Cloud account to application.properties to complete your configuration
you can find these information in:
Ibm cloud account -&amp;gt; services -&amp;gt; AppId -&amp;gt; Applications -&amp;gt; Add Application (if not done before) -&amp;gt; View Credentials
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;spring.main.allow-bean-definition-overriding=true&lt;/span&gt;

&lt;span class="s"&gt;env.urlAppid= // OAuth server URL from IBM AppID account&lt;/span&gt;

&lt;span class="c1"&gt;# SECURITY OAUTH2 CLIENT (OAuth2ClientProperties)&lt;/span&gt;

&lt;span class="s"&gt;security.oauth2.client.accessTokenUri=${env.urlAppid}/token&lt;/span&gt;
&lt;span class="s"&gt;security.oauth2.client.userAuthorizationUri=${env.urlAppid}/authorization&lt;/span&gt;


&lt;span class="c1"&gt;# SECURITY OAUTH2 RESOURCES (ResourceServerProperties)&lt;/span&gt;
&lt;span class="s"&gt;security.oauth2.resource.userInfoUri=${env.urlAppid}/userinfo&lt;/span&gt;


&lt;span class="c1"&gt;## Setting to change in case of changing app id dev instance&lt;/span&gt;
&lt;span class="s"&gt;security.oauth2.client.client-id= // IBM AppId account client-id&lt;/span&gt;
&lt;span class="s"&gt;security.oauth2.client.client-secret= // IBM AppId secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Finally to Sign In and Signup you to make an HTTP Request to these endpoints:&lt;/li&gt;
&lt;li&gt;Sign In: &lt;code&gt;https://appid-oauth.eu-gb.bluemix.net/oauth/v3/{TenantId}/token&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;grant_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// don't change&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nl"&gt;RequestHeader&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
&lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Basic ClientId:Secret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nl"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
&lt;span class="na"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Signup: &lt;code&gt;https://appid-management.eu-gb.bluemix.net/management/v4/{TenantId}/cloud_directory/sign_up&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
&lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// don't change&lt;/span&gt;
&lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nl"&gt;RequestHeader&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
   &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bearer {IAM_TOKEN}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nl"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
&lt;span class="na"&gt;HttpStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's all folks !&lt;/p&gt;

</description>
      <category>ibmcloud</category>
      <category>springboot</category>
      <category>appid</category>
      <category>oidc</category>
    </item>
    <item>
      <title>[ 🇬🇧 ] Gitlab CI to Build and Push containers to registry</title>
      <dc:creator>bzinoun </dc:creator>
      <pubDate>Tue, 28 May 2019 16:31:26 +0000</pubDate>
      <link>https://forem.com/bzinoun/gitlab-ci-to-build-and-push-containers-to-registry-538a</link>
      <guid>https://forem.com/bzinoun/gitlab-ci-to-build-and-push-containers-to-registry-538a</guid>
      <description>&lt;p&gt;We all know that Gitlab CI build uses docker image to do the job, But have you ever tried to build a docker image inside gitlab CI build ?&lt;/p&gt;

&lt;p&gt;As we know gitlab CI start on docker container. So when we want to build a docker image inside gitlab CI build, it's docker in docker (DinD)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmryadbkj85tx1d9ynf91.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmryadbkj85tx1d9ynf91.gif" width="245" height="130"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Without transition lets take a look at the &lt;code&gt;.gitla-ci.yml&lt;/code&gt;  file :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker:latest&lt;/span&gt;
    &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;DOCKER_DRIVER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;overlay2&lt;/span&gt;
    &lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;
    &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker:dind&lt;/span&gt;
    &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# docker login needs the password to be passed through stdin for security&lt;/span&gt;
      &lt;span class="c1"&gt;# we use $CI_JOB_TOKEN here which is a special token provided by GitLab&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo -n $CI_JOB_TOKEN | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker version&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker info&lt;/span&gt;

    &lt;span class="na"&gt;after_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker logout registry.gitlab.com&lt;/span&gt;
    &lt;span class="na"&gt;Build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker pull $CI_REGISTRY_IMAGE:latest || &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;docker build&lt;/span&gt;
          &lt;span class="s"&gt;--pull&lt;/span&gt;
          &lt;span class="s"&gt;--cache-from $CI_REGISTRY_IMAGE:latest&lt;/span&gt;
          &lt;span class="s"&gt;--tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA&lt;/span&gt;
          &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA&lt;/span&gt;
    &lt;span class="na"&gt;Push_When_tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;
      &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# We want this job to be ran on tags only.&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;tags&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1 - Images &amp;amp; services
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker:latest&lt;/span&gt;
    &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;DOCKER_DRIVER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;overlay2&lt;/span&gt;
    &lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;
    &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker:dind&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
yaml&lt;/p&gt;

&lt;p&gt;We start by defining the docker image that will be used by GitlabCI build. In our case and as example we used the latest docker image . &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;image: docker:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️  In production for example , I don't recommend using &lt;code&gt;latest&lt;/code&gt;or&lt;code&gt;stable&lt;/code&gt; versions. For many reasons ... &lt;br&gt;
One of them is reproducibility, Another reason is we want our pipeline to work in 10 month or 10 years. If a new feature is needed , then an upgrade is planned .&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;DOCKER_DRIVER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;overlay2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
yaml&lt;br&gt;
When using &lt;code&gt;docker:dind&lt;/code&gt; , Docker uses the &lt;code&gt;vfs&lt;/code&gt; storage driver which copies the filesystem on every run. This is a very disk-intensive operation which can be avoided if a different driver is used, for example &lt;code&gt;overlay2&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 - before and after Script
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# docker login needs the password to be passed through stdin for security&lt;/span&gt;
      &lt;span class="c1"&gt;# we use $CI_JOB_TOKEN here which is a special token provided by GitLab&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo -n $CI_JOB_TOKEN | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker version&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker info&lt;/span&gt;

    &lt;span class="na"&gt;after_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker logout registry.gitlab.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
yaml&lt;br&gt;
Nothing special on this step  : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connection to Gitlab Registry&lt;/li&gt;
&lt;li&gt;Check docker daemon and config&lt;/li&gt;
&lt;li&gt;Logout from docker registry&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3 -  Build and Push
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;Build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker pull $CI_REGISTRY_IMAGE:latest || &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;

        &lt;span class="c1"&gt;# notice the cache-from, which is going to use the image we just pulled locally&lt;/span&gt;
        &lt;span class="c1"&gt;# the built image is tagged locally with the commit SHA, and then pushed to &lt;/span&gt;
        &lt;span class="c1"&gt;# the GitLab registry&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;docker build&lt;/span&gt;
          &lt;span class="s"&gt;--pull&lt;/span&gt;
          &lt;span class="s"&gt;--cache-from $CI_REGISTRY_IMAGE:latest&lt;/span&gt;
          &lt;span class="s"&gt;--tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA&lt;/span&gt;
          &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA&lt;/span&gt;

&lt;span class="s"&gt;We pull the last pushed image on the registry ; the `|| &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="s"&gt;` assure that the pipeline will not fail if no image was found .&lt;/span&gt; 

&lt;span class="s"&gt;After pulling the last image , this one will be used for the cache when building a new image using the `--cache-from` .&lt;/span&gt; 

&lt;span class="s"&gt;Then we push to registry with the image flagged with `$CI_COMMIT_SHA` that contains the commit SHA .&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
yaml&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 - Tag management
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;Push_When_tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;
      &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;tags&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
yaml&lt;br&gt;
We want to keep  our Git tags in sync with our Docker tags. That helps a lot when debugging and trying to reproduce specific version bugs . &lt;/p&gt;

&lt;p&gt;If you have not automated this, you probably have found yourself in the situation of wondering “which git tag is this image again?”.&lt;/p&gt;

&lt;p&gt;⚠️ This stage is triggered only when a tag is created .&lt;/p&gt;

</description>
      <category>gitlabci</category>
      <category>docker</category>
      <category>dind</category>
      <category>registry</category>
    </item>
  </channel>
</rss>
