Computer >> कंप्यूटर >  >> प्रोग्रामिंग >> बाश प्रोग्रामिंग

बाशो के साथ स्वचालित हेल्म परिनियोजन

हमारे कुछ एप्लिकेशन कुबेरनेट्स क्लस्टर में होस्ट किए जाते हैं, और हम तैनाती को स्वचालित करने के लिए GitLab कंटीन्यूअस इंटीग्रेशन (CI) का उपयोग करते हैं और अपने एप्लिकेशन को तैनात करने के लिए Helm 2 का उपयोग करते हैं। हेल्म चार्ट कुबेरनेट्स ऑब्जेक्ट YAML फ़ाइलों के टेम्प्लेट के भंडारण को सक्षम करते हैं, जो चर के साथ प्रोग्रामेटिक रूप से सेट किए जा सकते हैं, जब चार्ट का उपयोग तैनाती के दौरान किया जाता है। यह हमें महत्वपूर्ण रहस्यों को GitLab-संरक्षित पर्यावरण चर या हाशिकॉर्प वॉल्ट में संग्रहीत करने और CI परिनियोजन कार्य के भीतर उनका उपयोग करने की अनुमति देता है।

हमारा परिनियोजन कार्य परिनियोजन प्रक्रिया को चलाने के लिए बैश स्क्रिप्ट का उपयोग करता है। यह बैश स्क्रिप्ट कई सुविधाएँ प्रस्तुत करती है जो CI/CD परिवेश में उपयोग के लिए मूल्यवान हैं:

  1. यह CI/CD परिवेश के बाहर उपयोग की सुविधा प्रदान करता है। GitLab CI और अन्य CI सिस्टम CI टेक्स्ट फ़ाइल (.gitlab-ci.yml, उदाहरण के लिए) के "स्क्रिप्ट" खंड में निष्पादन योग्य शेल कोड की पंक्तियों के रूप में कार्य चरणों को संग्रहीत करते हैं। हालांकि यह सुनिश्चित करने के लिए उपयोगी है कि बुनियादी निष्पादन योग्य चरणों को बाहरी निर्भरता के बिना संग्रहीत किया जा सकता है, यह डेवलपर्स को परीक्षण या मैन्युअल परिनियोजन परिदृश्यों में समान कोड का उपयोग करने से रोकता है। इसके अलावा, इन स्क्रिप्ट अनुभागों में बैश सिस्टम की कई उन्नत सुविधाओं का आसानी से उपयोग नहीं किया जा सकता है।
  2. यह महत्वपूर्ण परिनियोजन प्रक्रियाओं की इकाई परीक्षण की सुविधा प्रदान करता है। कोई भी CI सिस्टम यह परीक्षण करने का तरीका प्रदान नहीं करता है कि परिनियोजन तर्क अपेक्षित रूप से कार्य करता है या नहीं। सावधानी से निर्मित बैश स्क्रिप्ट को BATS के साथ इकाई परीक्षण किया जा सकता है।
  3. यह स्क्रिप्ट के भीतर अलग-अलग कार्यों के पुन:उपयोग की सुविधा प्रदान करता है। अंतिम खंड एक गार्ड क्लॉज का उपयोग करता है, अगर [[ "${BASH_SOURCE[0]}" =="${0}" ]] , जो run_main . को रोकता है जब स्क्रिप्ट निष्पादित नहीं की जा रही है तो फ़ंक्शन को कॉल किया जा रहा है। यह स्क्रिप्ट को सोर्स करने की अनुमति देता है, जो तब उपयोगकर्ताओं को इसके भीतर कई उपयोगी व्यक्तिगत कार्यों का उपयोग करने की अनुमति देता है। यह उचित BATS परीक्षण के लिए महत्वपूर्ण है।
  4. यह संवेदनशील जानकारी की सुरक्षा के लिए पर्यावरण चर का उपयोग करता है और कई परियोजनाओं और परियोजना अनुप्रयोग वातावरण में स्क्रिप्ट को पुन:प्रयोज्य बनाता है। GitLab CI, GitLab CI रनर द्वारा चलाए जाने पर इनमें से कई पर्यावरण चर उपलब्ध कराता है। GitLab CI के बाहर स्क्रिप्ट का उपयोग करने से पहले इन्हें मैन्युअल रूप से सेट किया जाना चाहिए।

स्क्रिप्ट कुबेरनेट्स के लिए एक आवेदन के लिए एक हेल्म चार्ट को तैनात करने के लिए आवश्यक सभी कार्यों को करती है और क्यूबेक्टल और हेल्म का उपयोग करके तैनाती के लिए तैयार होने की प्रतीक्षा करती है। कुबेरनेट्स क्लस्टर में टिलर चलाने के बजाय हेल्म स्थानीय टिलर इंस्टॉलेशन के साथ चलता है। कुबेरनेट्स HELM_USER और HELM_PASSWORD Kubernetes CLUSTER_SERVER . में लॉग इन करने के लिए उपयोग किया जाता है और PROJECT_NAMESPACE . टिलर शुरू हो गया है, हेल्म को क्लाइंट-ओनली मोड में इनिशियलाइज़ किया गया है, और इसका रेपो अपडेट किया गया है। यह सुनिश्चित करने के लिए कि सिंटैक्स त्रुटियां गलती से नहीं हुई हैं, टेम्पलेट को हेल्म के साथ पंक्तिबद्ध किया गया है। तब टेम्पलेट को हेल्म अपग्रेड --इंस्टॉल . का उपयोग करके घोषणात्मक मोड में परिनियोजित किया जाता है . हेल्म --प्रतीक्षा ध्वज का उपयोग करके परिनियोजन के तैयार होने की प्रतीक्षा करता है ।

स्क्रिप्ट सुनिश्चित करती है कि कुछ टेम्पलेट चर परिनियोजन के दौरान सेट किए गए हैं और विशेष परियोजना-विशिष्ट चर को GitLab CI PROJECT_SPECIFIC_DEPLOY_ARGS में निर्दिष्ट करने की अनुमति देता है पर्यावरणपरिवर्ती तारक। परिनियोजन में आवश्यक सभी पर्यावरण चर को स्क्रिप्ट निष्पादन में जल्दी चेक किया जाता है, और यदि कोई गायब है तो स्क्रिप्ट गैर-शून्य निकास स्थिति के साथ बाहर निकलती है।

इस स्क्रिप्ट का उपयोग कई GitLab CI-होस्टेड प्रोजेक्ट्स में किया गया है। इसने हमें प्रत्येक प्रोजेक्ट में परिनियोजन तर्क के बजाय अपने कोड पर ध्यान केंद्रित करने में मदद की है।

स्क्रिप्ट

#!/bin/bash

# MIT License
#
# Copyright (c) 2019 Darin London
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

log_level_for()
{
  case "${1}" in
    "error")
      echo 1
      ;;

    "warn")
      echo 2
      ;;

    "debug")
      echo 3
      ;;

    "info")
      echo 4
      ;;
    *)
      echo -1
      ;;
  esac
}

current_log_level()
{
  log_level_for "${LOG_LEVEL}"
}

error()
{
  [ $(log_level_for "error") -le $(current_log_level) ] &&  echo "${1}" >&2
}

warn()
{
  [ $(log_level_for "warn") -le $(current_log_level) ] &&  echo "${1}" >&2
}

debug()
{
  [ $(log_level_for "debug") -le $(current_log_level) ] &&  echo "${1}" >&2
}

info()
{
  [ $(log_level_for "info") -le $(current_log_level) ] &&  echo "${1}" >&2
}

check_required_environment() {
  local required_env="${1}"

  for reqvar in $required_env
  do
    if [ -z "${!reqvar}" ]
    then
      error "missing ENVIRONMENT ${reqvar}!"
      return 1
    fi
  done
}

check_default_environment() {
  local required_env="${1}"

  for varpair in $required_env
  do
    local manual_environment=$(echo "${varpair}" | cut -d':' -f1)
    local default_if_not_set=$(echo "${varpair}" | cut -d':' -f2)
    if [ -z "${!manual_environment}" ] && [ -z "${!default_if_not_set}" ]
    then
      error "missing default ENVIRONMENT, set ${manual_environment} or ${default_if_not_set}!"
      return 1
    fi
  done
}

dry_run() {
  [ ${DRY_RUN} ] && info "skipping for dry run" && return
  return 1
}

init_tiller() {
  info "initializing local tiller"
  dry_run && return

  export TILLER_NAMESPACE=$PROJECT_NAMESPACE
  export HELM_HOST=localhost:44134
  # https://rimusz.net/tillerless-helm/
  # run tiller locally instead of in the cluster
  tiller --storage=secret &
  export TILLER_PID=$!
  sleep 1
  kill -0 ${TILLER_PID}
  if [ $? -gt 0 ]
  then
    error "tiller not running!"
    return 1
  fi
}

init_helm() {
  info "initializing helm"
  dry_run && return

  helm init --client-only
  if [ $? -gt 0 ]
  then
    error "could not initialize helm"
    return 1
  fi
}

init_helm_with_tiller() {
  init_tiller || return 1
  init_helm || return 1
  info "updating helm client repository information"
  dry_run && return
  helm repo update
  if [ $? -gt 0 ]
  then
    error "could not update helm repository information"
    return 1
  fi
}

decommission_tiller() {
  if [ -n "${TILLER_PID}" ]
  then
    kill ${TILLER_PID}
    if [ $? -gt 0 ]
    then
     return
    fi
  fi
}

check_required_deploy_arg_environment() {
  [ -z "${PROJECT_SPECIFIC_DEPLOY_ARGS}" ] && return
  for reqvar in ${PROJECT_SPECIFIC_DEPLOY_ARGS}
  do
    if [ -z ${!reqvar} ]
    then
      error "missing Deployment ENVIRONMENT ${reqvar} required!"
      return 1
    fi
  done
}

project_specific_deploy_args() {
  [ -z "${PROJECT_SPECIFIC_DEPLOY_ARGS}" ] && echo "" && return

  extraArgs=''
  for deploy_arg_key in ${PROJECT_SPECIFIC_DEPLOY_ARGS}
  do
    extraArgs="${extraArgs} --set $(echo "${deploy_arg_key}" | sed 's/__/\./g' | tr '[:upper:]' '[:lower:]')=${!deploy_arg_key}"
  done

  echo "${extraArgs}"
}

check_required_cluster_login_environment() {
  check_required_environment "HELM_TOKEN HELM_USER PROJECT_NAMESPACE CLUSTER_SERVER" || return 1
}

cluster_login() {
  info "authenticating ${HELM_USER} in ${PROJECT_NAMESPACE}"
  dry_run && return

  kubectl config set-cluster ci_kube --server="${CLUSTER_SERVER}" || return 1
  kubectl config set-credentials "${HELM_USER}" --token="${HELM_TOKEN}" || return 1
  kubectl config set-context ${PROJECT_NAMESPACE}-deploy  --cluster=ci_kube --namespace=${PROJECT_NAMESPACE} --user=${HELM_USER} || return 1
  kubectl config use-context ${PROJECT_NAMESPACE}-deploy || return 1
}

lint_template() {
  info "linting template"
  dry_run && return

  helm lint ${CI_PROJECT_DIR}/helm-chart/${CI_PROJECT_NAME}
}

check_required_image_pull_environment() {
  if [ "${CI_PROJECT_VISIBILITY}" == "public" ]
  then
    check_required_environment "CI_REGISTRY CI_DEPLOY_USER CI_DEPLOY_PASSWORD" || return 1
  fi
}

image_pull_settings() {
  if [ "${CI_PROJECT_VISIBILITY}" == "public" ]
  then
    echo ""
  else
    echo "--set registry.root=${CI_REGISTRY} --set registry.secret.username=${CI_DEPLOY_USER} --set registry.secret.password=${CI_DEPLOY_PASSWORD}"
  fi
}

deployment_name() {
  if [ -n "${DEPLOYMENT_NAME}" ]
  then
    echo "${DEPLOYMENT_NAME}"
  else
    echo "${CI_ENVIRONMENT_SLUG}-${CI_PROJECT_NAME}"
  fi
}

deploy_template() {
  info "deploying $(deployment_name) from template"
  if dry_run
  then
    info "helm upgrade --force --recreate-pods --debug --set image.repository=${CI_REGISTRY_IMAGE}/${CI_PROJECT_NAME} --set image.tag=${CI_COMMIT_SHORT_SHA} --set environment=${CI_ENVIRONMENT_NAME} --set-string git_commit=${CI_COMMIT_SHORT_SHA} --set git_ref=${CI_COMMIT_REF_SLUG} --set ci_job_id=${CI_JOB_ID} $(environment_url_settings) $(image_pull_settings) $(project_specific_deploy_args) --wait --install $(deployment_name) ${CI_PROJECT_DIR}/helm-chart/${CI_PROJECT_NAME}"
  else
    helm upgrade --force --recreate-pods --debug \
    --set image.repository="${CI_REGISTRY_IMAGE}/${CI_PROJECT_NAME}" \
    --set image.tag="${CI_COMMIT_SHORT_SHA}" \
    --set environment="${CI_ENVIRONMENT_NAME}" \
    --set-string git_commit="${CI_COMMIT_SHORT_SHA}" \
    --set git_ref="${CI_COMMIT_REF_SLUG}" \
    --set ci_job_id="${CI_JOB_ID}" \
    $(image_pull_settings) \
    $(project_specific_deploy_args) \
    --wait \
    --install $(deployment_name) ${CI_PROJECT_DIR}/helm-chart/${CI_PROJECT_NAME}
  fi
}

get_pods() {
  kubectl get pods -l ci_job_id="${CI_JOB_ID}"
}

watch_deployment() {
  local watch_deployment=$(deployment_name)
  if [ -n "${WATCH_DEPLOYMENT}" ]
  then
    watch_deployment="${WATCH_DEPLOYMENT}"
  fi
  info "waiting until deployment ${watch_deployment} is ready"
  dry_run && return

  kubectl rollout status deployment/${watch_deployment} -w || return 1
  sleep 5
  get_pods || return 1
  # see what has been deployed
  kubectl describe deployment -l app=${CI_PROJECT_NAME},environment=${CI_ENVIRONMENT_NAME},git_commit=${CI_COMMIT_SHORT_SHA} || return 1
  if [ -n "${CI_ENVIRONMENT_URL}" ]
  then
    kubectl describe service -l app=${CI_PROJECT_NAME},environment=${CI_ENVIRONMENT_NAME} || return 1
    kubectl describe route -l app=${CI_PROJECT_NAME},environment=${CI_ENVIRONMENT_NAME} || return 1
  fi
}

run_main() {
  check_required_environment "CI_PROJECT_NAME CI_PROJECT_DIR CI_COMMIT_REF_SLUG CI_REGISTRY_IMAGE CI_ENVIRONMENT_NAME CI_JOB_ID CI_COMMIT_SHORT_SHA" || return 1
  check_default_environment "WATCH_DEPLOYMENT:CI_ENVIRONMENT_SLUG" || return 1
  check_required_deploy_arg_environment || return 1
  check_required_cluster_login_environment || return 1
  check_required_image_pull_environment || return 1
  cluster_login
  if [ $? -gt 0 ]
  then
    error "could not login kubectl"
    return 1
  fi

  init_helm_with_tiller
  if [ $? -gt 0 ]
  then
    error "could not initialize helm"
    return 1
  fi

  lint_template
  if [ $? -gt 0 ]
  then
    error "linting failed"
    return 1
  fi

  deploy_template
  if [ $? -gt 0 ]
  then
    error "could not deploy template"
    return 1
  fi

  watch_deployment
  if [ $? -gt 0 ]
  then
    error "could not watch deployment"
    return 1
  fi

  decommission_tiller
  info "ALL Complete!"
  return
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]
then
  run_main
  if [ $? -gt 0 ]
  then
    exit 1
  fi
fi


  1. इस बैश स्क्रिप्ट के साथ इमेज प्रोसेसिंग को स्वचालित करें

    लेखक न केवल शब्दों के साथ काम करते हैं, उन्हें अक्सर छवियों के साथ काम करना पड़ता है। तकनीकी लेखन में प्रौद्योगिकी और प्रक्रियाओं को व्यक्त करने के लिए बहुत सारे स्क्रीनशॉट प्रस्तुत करना शामिल है। अलग-अलग प्रकाशन प्लैटफ़ॉर्म में इमेज के लिए अलग-अलग ज़रूरतें हो सकती हैं, जैसे कि इमेज फ़ॉर्मैट या फ़ाइ

  1. इस साधारण बैश स्क्रिप्ट के साथ घर पर दो तरफा दस्तावेज़ प्रिंट करें

    हमारे पास घर पर एक लेजर प्रिंटर है। यह Hewlett Packard LaserJet Pro CP1525nw कलर प्रिंटर एक पुराना मॉडल है, लेकिन यह एक बेहतरीन वर्कहॉर्स रहा है जो मज़बूती से और रंग में प्रिंट करता है। मैंने इसे कुछ साल पहले हमारे रास्पबेरी पाई का उपयोग प्रिंट सर्वर के रूप में किया था। लेज़रजेट मेरे गृह कार्यालय

  1. बैश स्क्रिप्टिंग परिचय ट्यूटोरियल 5 व्यावहारिक उदाहरणों के साथ

    हमारी चल रही यूनिक्स सेड और यूनिक्स Awk श्रृंखला के समान, हम बैश स्क्रिप्टिंग पर कई लेख पोस्ट करेंगे, जो सभी बैश स्क्रिप्टिंग तकनीकों को व्यावहारिक उदाहरणों के साथ कवर करेगा। शेल एक प्रोग्राम है, जो यूजर कमांड की व्याख्या करता है। कमांड या तो उपयोगकर्ता द्वारा सीधे दर्ज किए जाते हैं या शेल स्क्रिप्