Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,22 @@
final long timeoutTime, final long waitDuration) {
boolean running = false;
// Check if dashboard service is up running.
while (System.currentTimeMillis() < timeoutTime) {

Check warning on line 172 in plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/utils/KubernetesClusterUtil.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Reduce the total number of break and continue statements in this loop to use at most one.

See more on https://sonarcloud.io/project/issues?id=apache_cloudstack&issues=AZzWLDBpUd8x_waMzFbm&open=AZzWLDBpUd8x_waMzFbm&pullRequest=12776
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("Checking dashboard service for the Kubernetes cluster: %s to come up", kubernetesCluster));
LOGGER.debug(String.format("Checking dashboard service (Kubernetes Dashboard or Headlamp) for the Kubernetes cluster: %s to come up", kubernetesCluster));
}
// Check for Headlamp (new dashboard) in kube-system namespace
if (isKubernetesClusterAddOnServiceRunning(kubernetesCluster, ipAddress, port, user, sshKeyFile, "kube-system", "headlamp")) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(String.format("Headlamp dashboard service for the Kubernetes cluster %s is in running state", kubernetesCluster));
}
running = true;
break;
}
// For backward compatibility, check for Kubernetes Dashboard in kubernetes-dashboard namespace
if (isKubernetesClusterAddOnServiceRunning(kubernetesCluster, ipAddress, port, user, sshKeyFile, "kubernetes-dashboard", "kubernetes-dashboard")) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(String.format("Dashboard service for the Kubernetes cluster %s is in running state", kubernetesCluster));
LOGGER.info(String.format("Kubernetes Dashboard service for the Kubernetes cluster %s is in running state", kubernetesCluster));
}
running = true;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,16 +331,29 @@ write_files:
if [[ ${EXTERNAL_CNI_PLUGIN} == false ]]; then
/opt/bin/kubectl apply -f ${K8S_CONFIG_SCRIPTS_COPY_DIR}/network.yaml
fi
/opt/bin/kubectl apply -f ${K8S_CONFIG_SCRIPTS_COPY_DIR}/dashboard.yaml
if [ -f "${K8S_CONFIG_SCRIPTS_COPY_DIR}/headlamp.yaml" ]; then
echo "Installing Headlamp dashboard from ISO"
/opt/bin/kubectl apply -f ${K8S_CONFIG_SCRIPTS_COPY_DIR}/headlamp.yaml
elif [ -f "${K8S_CONFIG_SCRIPTS_COPY_DIR}/dashboard.yaml" ]; then
echo "Installing Kubernetes Dashboard from ISO"
/opt/bin/kubectl apply -f ${K8S_CONFIG_SCRIPTS_COPY_DIR}/dashboard.yaml
/opt/bin/kubectl create rolebinding admin-binding --role=admin --user=admin || true
/opt/bin/kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=admin || true
/opt/bin/kubectl create clusterrolebinding kubernetes-dashboard-ui --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:kubernetes-dashboard || true
else
echo "Warning: No dashboard YAML found in ISO (neither headlamp.yaml nor dashboard.yaml)"
fi
rm -rf "${K8S_CONFIG_SCRIPTS_COPY_DIR}"
else
### Online installation - use Headlamp by default ###
/opt/bin/kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(/opt/bin/kubectl version | base64 | tr -d '\n')"
/opt/bin/kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta6/aio/deploy/recommended.yaml
/opt/bin/kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/headlamp/v0.40.1/kubernetes-headlamp.yaml
/opt/bin/kubectl create serviceaccount headlamp-admin -n kube-system || true
/opt/bin/kubectl create clusterrolebinding headlamp-admin --clusterrole=cluster-admin --serviceaccount=kube-system:headlamp-admin || true
fi

/opt/bin/kubectl create rolebinding admin-binding --role=admin --user=admin || true
/opt/bin/kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=admin || true
/opt/bin/kubectl create clusterrolebinding kubernetes-dashboard-ui --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:kubernetes-dashboard || true

sudo touch /home/cloud/success
echo "true" > /home/cloud/success
Expand Down
15 changes: 8 additions & 7 deletions scripts/util/create-kubernetes-binaries-iso.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
set -e

if [ $# -lt 6 ]; then
echo "Invalid input. Valid usage: ./create-kubernetes-binaries-iso.sh OUTPUT_PATH KUBERNETES_VERSION CNI_VERSION CRICTL_VERSION WEAVENET_NETWORK_YAML_CONFIG DASHBOARD_YAML_CONFIG BUILD_NAME [ARCH] [ETCD_VERSION]"
echo "eg: ./create-kubernetes-binaries-iso.sh ./ 1.11.4 0.7.1 1.11.1 https://github.com/weaveworks/weave/releases/download/latest_release/weave-daemonset-k8s-1.11.yaml https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.0/src/deploy/recommended/kubernetes-dashboard.yaml setup-v1.11.4 amd64"
echo "Invalid input. Valid usage: ./create-kubernetes-binaries-iso.sh OUTPUT_PATH KUBERNETES_VERSION CNI_VERSION CRICTL_VERSION WEAVENET_NETWORK_YAML_CONFIG HEADLAMP_DASHBOARD_VERSION BUILD_NAME [ARCH] [ETCD_VERSION]"
echo "eg: ./create-kubernetes-binaries-iso.sh ./ 1.11.4 0.7.1 1.11.1 https://github.com/weaveworks/weave/releases/download/latest_release/weave-daemonset-k8s-1.11.yaml 0.40.1 setup-v1.11.4 amd64"
exit 1
fi

Expand Down Expand Up @@ -96,10 +96,11 @@ echo "Downloading network config ${NETWORK_CONFIG_URL}"
network_conf_file="${working_dir}/network.yaml"
curl -sSL ${NETWORK_CONFIG_URL} -o ${network_conf_file}

DASHBORAD_CONFIG_URL="${6}"
echo "Downloading dashboard config ${DASHBORAD_CONFIG_URL}"
dashboard_conf_file="${working_dir}/dashboard.yaml"
curl -sSL ${DASHBORAD_CONFIG_URL} -o ${dashboard_conf_file}
HEADLAMP_DASHBOARD_VERSION="${6}"
HEADLAMP_DASHBOARD_URL="https://raw.githubusercontent.com/kubernetes-sigs/headlamp/v${HEADLAMP_DASHBOARD_VERSION}/kubernetes-headlamp.yaml"
echo "Downloading Headlamp manifest from ${HEADLAMP_DASHBOARD_URL}"
headlamp_conf_file="${working_dir}/headlamp.yaml"
curl -sSL ${HEADLAMP_DASHBOARD_URL} -o ${headlamp_conf_file}

# TODO : Change the url once merged
AUTOSCALER_URL="https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/cloudstack/examples/cluster-autoscaler-standard.yaml"
Expand Down Expand Up @@ -135,7 +136,7 @@ mkdir -p "${working_dir}/docker"
output=`${k8s_dir}/kubeadm config images list --kubernetes-version=${RELEASE}`

# Don't forget about the yaml images !
for i in ${network_conf_file} ${dashboard_conf_file}
for i in ${network_conf_file} ${headlamp_conf_file}
do
images=`grep "image:" $i | cut -d ':' -f2- | tr -d ' ' | tr -d "'"`
output=`printf "%s\n" ${output} ${images}`
Expand Down
44 changes: 37 additions & 7 deletions ui/src/views/compute/KubernetesServiceTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,32 +66,62 @@
</a-timeline>
</a-card>
<a-card :title="$t('label.kubernetes.dashboard')">
<p><strong>Note:</strong> CloudStack Kubernetes clusters use <strong>Headlamp</strong> dashboard (deployed in <code>kube-system</code> namespace). For backward compatibility with older clusters using Kubernetes Dashboard, please check your cluster configuration.</p>
<a-timeline>
<a-timeline-item>
<p>
{{ $t('label.run.proxy.locally') }}<br><br>
<code><b>kubectl --kubeconfig /custom/path/kube.conf proxy</b></code>
<strong>Access Headlamp Dashboard (new clusters)</strong><br><br>
<strong>Step 1:</strong> Run port-forward command:<br>
<code><b>kubectl --kubeconfig /custom/path/kube.conf port-forward -n kube-system service/headlamp 8080:80</b></code><br><br>
<strong>Step 2:</strong> Open in your browser:<br>
<a href="http://localhost:8080"><code>http://localhost:8080</code></a>
</p>
</a-timeline-item>
<a-timeline-item>
<p>
{{ $t('label.open.url') }}<br><br>
<strong>Access Kubernetes Dashboard (legacy clusters)</strong><br><br>
<strong>Step 1:</strong> {{ $t('label.run.proxy.locally') }}<br>
<code><b>kubectl --kubeconfig /custom/path/kube.conf proxy</b></code><br><br>
<strong>Step 2:</strong> {{ $t('label.open.url') }}<br>
<a href="http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/"><code>http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/</code></a>
</p>
</a-timeline-item>
<a-timeline-item>
<p>
<strong>Create Access Token for Headlamp (new clusters)</strong>
</p>
<p v-html="$t('label.kubernetes.dashboard.create.token')"></p>
<p v-html="$t('label.kubernetes.dashboard.create.token.desc')"></p>
<a-textarea :value="'kubectl --kubeconfig /custom/path/kube.conf apply -f - <<EOF\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: kubernetes-dashboard-admin-user\n namespace: kubernetes-dashboard\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n name: kubernetes-dashboard-admin-user\nroleRef:\n apiGroup: rbac.authorization.k8s.io\n kind: ClusterRole\n name: cluster-admin\nsubjects:\n- kind: ServiceAccount\n name: kubernetes-dashboard-admin-user\n namespace: kubernetes-dashboard\n---\napiVersion: v1\nkind: Secret\ntype: kubernetes.io/service-account-token\nmetadata:\n name: kubernetes-dashboard-token\n namespace: kubernetes-dashboard\n annotations:\n kubernetes.io/service-account.name: kubernetes-dashboard-admin-user\nEOF'" :rows="10" readonly />
<a-textarea :value="'kubectl --kubeconfig /custom/path/kube.conf apply -f - <<EOF\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: headlamp-admin\n namespace: kube-system\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n name: headlamp-admin\nroleRef:\n apiGroup: rbac.authorization.k8s.io\n kind: ClusterRole\n name: cluster-admin\nsubjects:\n- kind: ServiceAccount\n name: headlamp-admin\n namespace: kube-system\n---\napiVersion: v1\nkind: Secret\ntype: kubernetes.io/service-account-token\nmetadata:\n name: headlamp-admin-token\n namespace: kube-system\n annotations:\n kubernetes.io/service-account.name: headlamp-admin\nEOF'" :rows="12" readonly />
<br><br>
<p>{{ $t('label.token.for.dashboard.login') }}:</p>
<code><b>kubectl --kubeconfig /custom/path/kube.conf describe secret headlamp-admin-token -n kube-system</b></code>
</a-timeline-item>
<a-timeline-item>
<p>
<strong>Create Access Token for Kubernetes Dashboard (legacy clusters)</strong>
</p>
<p v-html="$t('label.kubernetes.dashboard.create.token.desc')"></p>
<a-textarea :value="'kubectl --kubeconfig /custom/path/kube.conf apply -f - <<EOF\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: kubernetes-dashboard-admin-user\n namespace: kubernetes-dashboard\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n name: kubernetes-dashboard-admin-user\nroleRef:\n apiGroup: rbac.authorization.k8s.io\n kind: ClusterRole\n name: cluster-admin\nsubjects:\n- kind: ServiceAccount\n name: kubernetes-dashboard-admin-user\n namespace: kubernetes-dashboard\n---\napiVersion: v1\nkind: Secret\ntype: kubernetes.io/service-account-token\nmetadata:\n name: kubernetes-dashboard-token\n namespace: kubernetes-dashboard\n annotations:\n kubernetes.io/service-account.name: kubernetes-dashboard-admin-user\nEOF'" :rows="12" readonly />
<br><br>
<p>{{ $t('label.token.for.dashboard.login') }}:</p>
<code><b>kubectl --kubeconfig /custom/path/kube.conf describe secret kubernetes-dashboard-token -n kubernetes-dashboard</b></code>
</a-timeline-item>
<a-timeline-item>
<p>
{{ $t('label.token.for.dashboard.login') }}<br><br>
<code><b>kubectl --kubeconfig /custom/path/kube.conf describe secret $(kubectl --kubeconfig /custom/path/kube.conf get secrets -n kubernetes-dashboard | grep kubernetes-dashboard-token | awk '{print $1}') -n kubernetes-dashboard</b></code>
<strong>Important Notes:</strong><br>
• <strong>Port-forwarding is recommended for Headlamp</strong> - simpler and more reliable than kubectl proxy<br>
• Token is only needed if accessing Headlamp via NodePort or LoadBalancer with external access<br>
• For Kubernetes 1.24+, service account tokens are no longer auto-generated - use the Secret resource shown above or <code>kubectl create token</code> command<br>
• <strong>Cluster-admin role grants full control</strong> - use with caution and only for trusted administrators<br>
• Keep the port-forward command running while using the dashboard (press Ctrl+C to stop)
</p>
</a-timeline-item>
</a-timeline>
<p>{{ $t('label.more.access.dashboard.ui') }}, <a href="https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/#accessing-the-dashboard-ui">https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/#accessing-the-dashboard-ui</a></p>
<p>{{ $t('label.more.access.dashboard.ui') }}:
<a href="https://headlamp.dev/docs/latest/">Headlamp Documentation</a> |
<a href="https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/#accessing-the-dashboard-ui">Kubernetes Dashboard (Legacy)</a>
</p>
</a-card>
<a-card :title="$t('label.access.kubernetes.nodes')">
<p v-html="$t('label.kubernetes.access.details')"></p>
Expand Down
Loading