You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

254 lines
10 KiB

  1. #!/usr/bin/env bash
  2. # http://redsymbol.net/articles/unofficial-bash-strict-mode
  3. set -euo pipefail
  4. usage()
  5. {
  6. cat <<END
  7. deploy.sh: deploys the $app_name application to a Kubernetes cluster using Helm.
  8. Parameters:
  9. --aks-name <AKS cluster name>
  10. The name of the AKS cluster. Required when the registry (using the -r parameter) is set to "aks".
  11. --aks-rg <AKS resource group>
  12. The resource group for the AKS cluster. Required when the registry (using the -r parameter) is set to "aks".
  13. -b | --build-solution
  14. Force a solution build before deployment (default: false).
  15. -d | --dns <dns or ip address> | --dns aks
  16. Specifies the external DNS/ IP address of the Kubernetes cluster.
  17. If 'aks' is set as value, the DNS value is retrieved from the AKS. --aks-name and --aks-rg are needed.
  18. When --use-local-k8s is specified the external DNS is automatically set to localhost.
  19. -h | --help
  20. Displays this help text and exits the script.
  21. --image-build
  22. Build images (default is to not build all images).
  23. --image-push
  24. Upload images to the container registry (default is not pushing to the custom registry)
  25. -n | --app-name <the name of the app>
  26. Specifies the name of the application (default: eshop).
  27. --namespace <namespace name>
  28. Specifies the namespace name to deploy the app. If it doesn't exists it will be created (default: eshop).
  29. -p | --docker-password <docker password>
  30. The Docker password used to logon to the custom registry, supplied using the -r parameter.
  31. -r | --registry <container registry>
  32. Specifies the container registry to use (required), e.g. myregistry.azurecr.io.
  33. --skip-clean
  34. Do not clean the Kubernetes cluster (default is to clean the cluster).
  35. --skip-infrastructure
  36. Do not deploy infrastructure resources (like sql-data, no-sql or redis).
  37. This is useful for production environments where infrastructure is hosted outside the Kubernetes cluster.
  38. -t | --tag <docker image tag>
  39. The tag used for the newly created docker images. Default: latest.
  40. -u | --docker-username <docker username>
  41. The Docker username used to logon to the custom registry, supplied using the -r parameter.
  42. --use-local-k8s
  43. Deploy to a locally installed Kubernetes (default: false).
  44. --use-mesh
  45. Use Linkerd as service mesh
  46. --image-pull-policy <policy>
  47. Image Pull Policy: Always, IfNotPresent, Never (default: Always)
  48. It is assumed that the Kubernetes cluster has been granted access to the container registry.
  49. If using AKS and ACR see link for more info:
  50. https://docs.microsoft.com/en-us/azure/container-registry/container-registry-auth-aks
  51. WARNING! THE SCRIPT WILL COMPLETELY DESTROY ALL DEPLOYMENTS AND SERVICES VISIBLE
  52. FROM THE CURRENT CONFIGURATION CONTEXT AND NAMESPACE.
  53. It is recommended that you check your selected namespace, 'eshop' by default, is already in use.
  54. Every deployment and service done in the namespace will be deleted.
  55. For more information see https://kubernetes.io/docs/tasks/administer-cluster/namespaces/
  56. END
  57. }
  58. app_name='eshop'
  59. aks_name=''
  60. aks_rg=''
  61. build_images=''
  62. clean='yes'
  63. build_solution=''
  64. container_registry=''
  65. docker_password=''
  66. docker_username=''
  67. dns=''
  68. image_tag='latest'
  69. push_images=''
  70. skip_infrastructure=''
  71. use_local_k8s=''
  72. namespace='eshop'
  73. use_mesh='false'
  74. ingressMeshAnnotationsFile='ingress_values_linkerd.yaml'
  75. imagePullPolicy='Always'
  76. while [[ $# -gt 0 ]]; do
  77. case "$1" in
  78. --aks-name )
  79. aks_name="$2"; shift 2;;
  80. --aks-rg )
  81. aks_rg="$2"; shift 2;;
  82. -b | --build-solution )
  83. build_solution='yes'; shift ;;
  84. -d | --dns )
  85. dns="$2"; shift 2;;
  86. -h | --help )
  87. usage; exit 1 ;;
  88. -n | --app-name )
  89. app_name="$2"; shift 2;;
  90. -p | --docker-password )
  91. docker_password="$2"; shift 2;;
  92. -r | --registry )
  93. container_registry="$2"; shift 2;;
  94. --skip-clean )
  95. clean=''; shift ;;
  96. --image-build )
  97. build_images='yes'; shift ;;
  98. --image-push )
  99. push_images='yes'; shift ;;
  100. --skip-infrastructure )
  101. skip_infrastructure='yes'; shift ;;
  102. -t | --tag )
  103. image_tag="$2"; shift 2;;
  104. -u | --docker-username )
  105. docker_username="$2"; shift 2;;
  106. --use-local-k8s )
  107. use_local_k8s='yes'; shift ;;
  108. --namespace )
  109. namespace="$2"; shift 2;;
  110. --use-mesh )
  111. use_mesh='true'; shift ;;
  112. --image-pull-policy )
  113. imagePullPolicy="$2"; shift 2;;
  114. *)
  115. echo "Unknown option $1"
  116. usage; exit 2 ;;
  117. esac
  118. done
  119. if [[ $imagePullPolicy != "Always" && $imagePullPolicy != "Never" && $imagePullPolicy != "IfNotPresent" ]]; then
  120. echo "--image-pull-policy needs to be a valid value: Always, IfNotPresent, Never"
  121. usage; exit 2;
  122. fi
  123. if [[ $build_solution ]]; then
  124. echo "#################### Building $app_name solution ####################"
  125. dotnet publish -o obj/Docker/publish ../../eShopOnContainers-ServicesAndWebApps.sln
  126. fi
  127. export TAG=$image_tag
  128. if [[ $build_images ]]; then
  129. echo "#################### Building the $app_name Docker images ####################"
  130. docker-compose -p ../.. -f ../../docker-compose.yml build
  131. # Remove temporary images
  132. docker rmi $(docker images -qf "dangling=true")
  133. fi
  134. use_custom_registry=''
  135. if [[ -n $container_registry ]]; then
  136. echo "################ Log into custom registry $container_registry ##################"
  137. use_custom_registry='yes'
  138. if [[ -z $docker_username ]] || [[ -z $docker_password ]]; then
  139. echo "Error: Must use -u (--docker-username) AND -p (--docker-password) if specifying custom registry"
  140. exit 1
  141. fi
  142. docker login -u $docker_username -p $docker_password $container_registry
  143. fi
  144. if [[ $push_images ]]; then
  145. echo "#################### Pushing images to the container registry ####################"
  146. services=(basket.api catalog.api identity.api ordering.api payment.api webmvc webspa webstatus)
  147. if [[ -z "$(docker image ls -q --filter=reference=eshop/$service:$image_tag)" ]]; then
  148. image_tag=linux-$image_tag
  149. fi
  150. for service in "${services[@]}"
  151. do
  152. echo "Pushing image for service $service..."
  153. docker tag "eshop/$service:$image_tag" "$container_registry/$service:$image_tag"
  154. docker push "$container_registry/$service:$image_tag"
  155. done
  156. fi
  157. ingress_values_file="ingress_values.yaml"
  158. if [[ $use_local_k8s ]]; then
  159. ingress_values_file="ingress_values_dockerk8s.yaml"
  160. dns="localhost"
  161. fi
  162. if [[ $dns == "aks" ]]; then
  163. echo "#################### Begin AKS discovery based on the --dns aks setting. ####################"
  164. if [[ -z $aks_name ]] || [[ -z $aks_rg ]]; then
  165. echo "Error: When using -dns aks, MUST set -aksName and -aksRg too."
  166. echo ''
  167. usage
  168. exit 1
  169. fi
  170. echo "Getting AKS cluster $aks_name AKS (in resource group $aks_rg)"
  171. # JMESPath queries are case sensitive and httpapplicationrouting can be lowercase sometimes
  172. jmespath_dnsqueries=(\
  173. addonProfiles.httpApplicationRouting.config.HTTPApplicationRoutingZoneName \
  174. addonProfiles.httpapplicationrouting.config.HTTPApplicationRoutingZoneName \
  175. )
  176. for q in "${jmespath_dnsqueries[@]}"
  177. do
  178. dns="$(az aks show -n $aks_name -g $aks_rg --query $q -o tsv)"
  179. if [[ -n $dns ]]; then break; fi
  180. done
  181. if [[ -z $dns ]]; then
  182. echo "Error: when getting DNS of AKS $aks_name (in resource group $aks_rg). Please ensure AKS has httpRouting enabled AND Azure CLI is logged in and is of version 2.0.37 or higher."
  183. exit 1
  184. fi
  185. echo "DNS base found is $dns. Will use $aks_name.$dns for the app!"
  186. dns="$aks_name.$dns"
  187. fi
  188. # Initialization & check commands
  189. if [[ -z $dns ]]; then
  190. echo "No DNS specified. Ingress resources will be bound to public IP."
  191. fi
  192. if [[ $clean ]]; then
  193. echo "Cleaning previous helm releases..."
  194. if [[ -z $(helm ls -q --namespace $namespace) ]]; then
  195. echo "No previous releases found"
  196. else
  197. helm --namespace $namespace uninstall $(helm ls -q --namespace $namespace)
  198. echo "Previous releases deleted"
  199. waitsecs=10; while [ $waitsecs -gt 0 ]; do echo -ne "$waitsecs\033[0K\r"; sleep 1; : $((waitsecs--)); done
  200. fi
  201. fi
  202. echo "#################### Begin $app_name installation using Helm ####################"
  203. infras=(sql-data nosql-data rabbitmq keystore-data basket-data)
  204. charts=(eshop-common basket-api catalog-api identity-api mobileshoppingagg ordering-api ordering-backgroundtasks ordering-signalrhub payment-api webmvc webshoppingagg webspa webstatus webhooks-api webhooks-web)
  205. gateways=(apigwms apigwws)
  206. if [[ !$skip_infrastructure ]]; then
  207. for infra in "${infras[@]}"
  208. do
  209. echo "Installing infrastructure: $infra"
  210. helm install "$app_name-$infra" --namespace $namespace --set "ingress.hosts={$dns}" --values app.yaml --values inf.yaml --values $ingress_values_file --values $ingressMeshAnnotationsFile --set app.name=$app_name --set inf.k8s.dns=$dns $infra --set inf.mesh.enabled=$use_mesh
  211. done
  212. fi
  213. for chart in "${charts[@]}"
  214. do
  215. echo "Installing: $chart"
  216. if [[ $use_custom_registry ]]; then
  217. helm install "$app_name-$chart" --namespace $namespace --set "ingress.hosts={$dns}" --set inf.registry.server=$container_registry --set inf.registry.login=$docker_username --set inf.registry.pwd=$docker_password --set inf.registry.secretName=eshop-docker-scret --values app.yaml --values inf.yaml --values $ingress_values_file --values $ingressMeshAnnotationsFile --set app.name=$app_name --set inf.k8s.dns=$dns --set image.tag=$image_tag --set image.pullPolicy=$imagePullPolicy $chart --set inf.mesh.enabled=$use_mesh
  218. elif [[ $chart != "eshop-common" ]]; then # eshop-common is ignored when no secret must be deployed
  219. helm install "$app_name-$chart" --namespace $namespace --set "ingress.hosts={$dns}" --values app.yaml --values inf.yaml --values $ingress_values_file --values $ingressMeshAnnotationsFile --set app.name=$app_name --set inf.k8s.dns=$dns --set image.tag=$image_tag --set image.pullPolicy=$imagePullPolicy $chart --set inf.mesh.enabled=$use_mesh
  220. fi
  221. done
  222. for gw in "${gateways[@]}"
  223. do
  224. echo "Installing gateway: $gw"
  225. helm install "$app_name-$gw" --namespace $namespace --set "ingress.hosts={$dns}" --values app.yaml --values inf.yaml --values $ingress_values_file --set app.name=$app_name --set inf.k8s.dns=$dns --set image.pullPolicy=$imagePullPolicy $gw
  226. done
  227. echo "FINISHED: Helm charts installed."