- 文档
- 教程
- DevOps
- 运维
【免费下载链接】devops-exercises
Linux, Jenkins, AWS, SRE, Prometheus, Docker, Python, Ansible, Git, Kubernetes, Terraform, OpenStack, SQL, NoSQL, Azure, GCP, DNS, Elastic, Network, Virtualization. DevOps Interview Questions
导读
本文以 topics/pipeline_deploy_image_to_k8.md 中的练习题为核心,完整讲解如何在任意 CI/CD 系统上编写一条"从 Dockerfile 构建镜像 → 推送镜像仓库 → 发布到运行中的 Kubernetes 集群"的自动化管道。仓库中配套的 topics/cicd/deploy_to_kubernetes.md 及其解决方案提供了可运行的 Jenkins + Ansible + Kubernetes 参考实现,读完本文你将掌握声明式 Jenkinsfile 的阶段划分、镜像构建与多标签推送、基于 Ansible 的 HTTPS 证书生成与 k8s 资源下发,以及 Deployment/Service/Ingress 三类核心资源的一体化编排。
一、练习题目标解析
先明确题目要求(topics/pipeline_deploy_image_to_k8.md):
Write a pipeline, on any CI/CD system you prefer, that will build an image out of a given Dockerfile and will publish that image to running Kubernetes cluster.
题目本身刻意保持开放,关键约束有三点:
- 任意 CI/CD 系统:不限定 Jenkins、GitLab CI、GitHub Actions 等具体平台,考察的是对管道抽象阶段的理解;
- 从给定 Dockerfile 构建镜像:管道必须能消费源码仓库中的 Dockerfile 产出容器镜像;
- 发布到"运行中的"Kubernetes 集群:强调镜像不只是构建产物,还要真正落到集群中运行,即"发布/部署"闭环。
仓库中的配套练习 topics/cicd/deploy_to_kubernetes.md 给出了更具体的要求,可作为本题的验收基准:
- 管道将部署一个 "hello world" Web 应用到 Kubernetes;
- CI/CD 系统与 Kubernetes 集群分别位于不同系统(体现"构建环境与运行环境分离"的生产理念);
- Web 应用必须可通过 HTTPS 远程访问。
这两个练习互为表里:前者侧重"镜像构建与发布",后者侧重"跨系统部署与 HTTPS 暴露"。仓库解决方案将两者合并为一条完整链路,本文按此链路展开。
二、整体架构与关键决策
从仓库解决方案 topics/cicd/solutions/deploy_to_kubernetes/README.md 可以还原出如下拓扑:
[代码仓库 Git] ──> [Jenkins(CI/CD 系统)] │ stage 1: Checkout Source │ stage 2: Build image ──> Docker 引擎 │ stage 3: Push image ──> Docker Hub 镜像仓库 │ stage 4: Deploy App ──> ansible-playbook deploy.yml │ │ │ ▼ └──> [远程 Kubernetes 集群(minikube 等)] · 生成自签名 SSL 证书并创建 TLS Secret · 应用 Deployment / Service / Ingress该架构印证了几个重要设计决策:
- 构建与运行分离:Jenkins 与 Kubernetes 集群不在同一系统,管道通过 Ansible 控制远程集群,满足"CI/CD 系统与集群分离"的硬性要求;
- 镜像仓库作为中间态:镜像先推送到 Registry(默认 Docker Hub),集群侧通过
imagePullPolicy: Always拉取,避免集群节点本地缓存导致的版本陈旧问题; - 证书生成自动化:HTTPS 证书由 Ansible playbook 在集群侧实时生成(自签名),再灌入 Kubernetes Secret,配合 Ingress 的 TLS 配置完成 HTTPS 暴露。
三、环境与前置准备
参照解决方案 topics/cicd/solutions/deploy_to_kubernetes/README.md 的步骤 1-2:
- Jenkins 系统:按标准流程安装 Jenkins(需安装 Pipeline、Git、Docker 等插件,以及 Ansible 命令行工具);
- Kubernetes 集群:在远程主机部署集群,minikube 是最快捷的本地验证方式;集群侧需预装
kubectl,并确保 Jenkins 侧有可用的 kubeconfig(解决方案中 Ansible 的k8s模块通过kubeconfig: '/home/abregman/.kube/config'指定); - 镜像仓库账号:准备 Docker Hub 账号(或任何支持 Registry API 的仓库),管道中的
docker.withRegistry('https://registry.hub.docker.com', 'dockerhub')需要仓库凭据 ID 为dockerhub的 Jenkins 凭据; - Ansible 依赖:部署节点需要
kubernetes.core集合(提供k8s模块)与openssl相关模块支持。
四、示例应用与容器化
解决方案附带一个极简 "Hello World" 页面 topics/cicd/solutions/deploy_to_kubernetes/html/index.html,仅包含红色标题Hello World :),引用本地css/normalize.css、css/skeleton.css与images/favicon.png。练习要求"给定一个 Dockerfile",你需要在 Web 应用仓库根目录编写对应的 Dockerfile(例如基于 nginx 或 python:alpine 构建,将上述静态页打入镜像,并暴露 80/443 端口——与后续 helloworld.yml 中声明的containerPort: 80/443对应)。
关于容器化本身,仓库 topics/containers/README.md 提供了可参考的最佳实践:FROM指令指定带 tag 的 base 镜像、只安装应用必需依赖、用&&合并RUN指令减小镜像体积、镜像构建缓存机制等。这些实践直接决定了镜像构建阶段的效率与产物质量。
五、Jenkins 声明式管道详解
核心实现位于 topics/cicd/solutions/deploy_to_kubernetes/Jenkinsfile。它采用声明式(Declarative)语法,划分为四个阶段:
pipeline { agent any stages { stage('Checkout Source') { steps { git url:'https://github.com/<GITHUB_USERNAME>/<YOUR_WEB_APP_REPO>.git', // credentialsId: 'creds_github', branch:'master' } } stage("Build image") { steps { script { myapp = docker.build("<YOUR_DOCKER_USERNAME>/helloworld:${env.BUILD_ID}") } } } stage("Push image") { steps { script { docker.withRegistry('https://registry.hub.docker.com', 'dockerhub') { myapp.push("latest") myapp.push("${env.BUILD_ID}") } } } } stage('Deploy App') { steps { script { sh 'ansible-playbook deploy.yml' } } } } }5.1 Checkout Source:拉取源码
使用git步骤拉取 Web 应用仓库。其中<GITHUB_USERNAME>、<YOUR_WEB_APP_REPO>为占位符,需替换为真实仓库地址;如需私有仓库认证,可取消注释credentialsId: 'creds_github'并配置对应 Jenkins 凭据。此阶段为后续docker.build提供构建上下文(Dockerfile 及静态资源)。
5.2 Build image:根据 Dockerfile 构建镜像
myapp = docker.build("<YOUR_DOCKER_USERNAME>/helloworld:${env.BUILD_ID}")docker.build会读取当前工作目录(即 Checkout 出的源码根目录)下的 Dockerfile 完成构建;- 镜像名使用
<DOCKER_USERNAME>/helloworld命名空间,镜像 tag 采用${env.BUILD_ID}——即本次 Jenkins 构建的序号。这一设计保证了每次构建的镜像 tag 全局唯一,为后续精确回滚和版本追踪提供基础; docker.build返回的myapp对象被保存,供 Push 阶段复用(同一镜像对象可打多个 tag)。
5.3 Push image:推送镜像仓库
docker.withRegistry('https://registry.hub.docker.com', 'dockerhub') { myapp.push("latest") myapp.push("${env.BUILD_ID}") }docker.withRegistry(registryUrl, credentialsId)在指定 Registry 上下文中执行推送,'dockerhub'是 Jenkins 中保存 Docker Hub 账号密码的凭据 ID;- 一次构建同时推送两个 tag:
latest(滚动追踪最新构建)与${env.BUILD_ID}(固化本次构建版本)。这种"latest + 版本号"双标签策略是镜像发布的标准做法——latest便于集群侧默认拉取,版本号 tag 便于精确定位与回滚; - 推送成功后,镜像对运行中的 Kubernetes 集群可见,为 Deploy 阶段铺路。
5.4 Deploy App:Ansible 下发部署
sh 'ansible-playbook deploy.yml'Deploy 阶段直接调用仓库根目录下的 deploy.yml 执行 Ansible playbook。注意:Jenkinsfile 与 deploy.yml 位于同一仓库目录(仓库中两者同处 topics/cicd/solutions/deploy_to_kubernetes/),Checkout 后deploy.yml即存在于工作目录,sh可直接引用。
六、Ansible Playbook:从证书到资源下发
deploy.yml 是整个部署闭环的核心,承担"生成证书 → 创建 Secret → 下发 k8s 资源"三件事:
- name: Apply Kubernetes YAMLs hosts: kubernetes tasks: - name: Ensure SSL related directories exist file: path: "{{ item }}" state: directory loop: - "/etc/ssl/crt" - "/etc/ssl/csr" - "/etc/ssl/private" - name: Generate an OpenSSL private key. openssl_privatekey: path: /etc/ssl/private/privkey.pem - name: generate openssl certificate signing requests openssl_csr: path: /etc/ssl/csr/hello-world.app.csr privatekey_path: /etc/ssl/private/privkey.pem common_name: hello-world.app - name: Generate a Self Signed OpenSSL certificate openssl_certificate: path: /etc/ssl/crt/hello-world.app.crt privatekey_path: /etc/ssl/private/privkey.pem csr_path: /etc/ssl/csr/hello-world.app.csr provider: selfsigned - name: Create k8s secret command: "kubectl create secret tls tls-secret --cert=/etc/ssl/crt/hello-world.app.crt --key=/etc/ssl/private/privkey.pem" register: result failed_when: - result.rc == 2 - name: Deploy web app k8s: state: present definition: "{{ lookup('file', './helloworld.yml') }}" kubeconfig: '/home/abregman/.kube/config' namespace: 'default' wait: true6.1 证书三件套:私钥 → CSR → 自签名证书
playbook 按标准 OpenSSL 流程在集群主机上生成证书:
openssl_privatekey生成私钥/etc/ssl/private/privkey.pem;openssl_csr基于该私钥生成证书签名请求,common_name: hello-world.app与后续 Ingress 的host: hello-world.app严格对应;openssl_certificate以provider: selfsigned直接自签证书/etc/ssl/crt/hello-world.app.crt,形成完整的私钥 + 证书对。
6.2 创建 TLS Secret
command: "kubectl create secret tls tls-secret --cert=... --key=..." register: result failed_when: - result.rc == 2用kubectl create secret tls将证书对封装为名为tls-secret的 Kubernetes TLS Secret。failed_when只在rc == 2时判定失败——这样当 Secret 已存在导致命令报错(rc 非 0)时,管道不会因幂等性问题中断,保证 playbook 可重复执行。
6.3 k8s 模块下发资源
k8s: state: present definition: "{{ lookup('file', './helloworld.yml') }}" kubeconfig: '/home/abregman/.kube/config' namespace: 'default' wait: truedefinition通过lookup('file', ...)读取同目录的 helloworld.yml,把整份多资源 YAML 交给k8s模块;kubeconfig指向集群管理员的 kubeconfig 路径(示例为/home/abregman/.kube/config,需按实际环境替换);wait: true让 Ansible 等待资源达到就绪状态后再返回,确保管道后续步骤(如远程访问验证)不会因资源未就绪而失败。
集群侧的节点清单由 inventory 定义:
[kubernetes] x.x.x.xhosts: kubernetes即匹配此分组,将x.x.x.x替换为真实集群地址即可。
七、Kubernetes 资源定义:Deployment、Service、Ingress
helloworld.yml 在一个文件中声明三类资源,完整覆盖"运行、暴露、HTTPS"三个诉求。
7.1 Deployment:定义应用运行形态
apiVersion: apps/v1 kind: Deployment metadata: name: hello-blue-whale spec: replicas: 3 selector: matchLabels: app: hello-world-app version: blue template: metadata: name: hello-blue-whale-pod labels: app: hello-world-app version: blue spec: containers: - name: hello-whale-container image: abregman2/helloworld:latest imagePullPolicy: Always ports: - containerPort: 80 - containerPort: 443- 副本与标签:
replicas: 3保证 3 个 Pod 提供高可用;selector.matchLabels与 Podlabels必须一致,这是 Deployment 管理 Pod 的匹配依据;version: blue表明此清单可按蓝绿(blue/green)发布模式扩展; - 镜像与拉取策略:
image: abregman2/helloworld:latest与管道 Push 阶段推送的镜像命名一致;imagePullPolicy: Always强制每次创建 Pod 都从 Registry 拉取最新镜像,避免集群节点缓存旧镜像——这正是"镜像由管道构建并发布到集群"闭环的关键一环; - 端口声明:同时暴露 80(HTTP)与 443(HTTPS),与 Ingress 的 TLS 终止对应。
7.2 Service:集群内稳定访问入口
apiVersion: v1 kind: Service metadata: name: hello-world labels: app: hello-world-app spec: ports: - port: 80 targetPort: 80 protocol: TCP name: http selector: app: hello-world-appService 通过selector: app: hello-world-app关联 Deployment 管理的全部 Pod,port: 80为服务端口,targetPort: 80转发到容器端口,为 Ingress 提供稳定的后端访问点。
7.3 Ingress:HTTPS 远程暴露
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example-ingress annotations: cert-manager.io/cluster-issuer: selfsigned-issuer nginx.ingress.kubernetes.io/rewrite-target: / kubernetes.io/ingress.class: nginx spec: tls: - hosts: - hello-world.app secretName: shhh rules: - host: hello-world.app http: paths: - path: / pathType: Prefix backend: service: name: hello-world port: number: 80- TLS 终止:
spec.tls声明hello-world.app域名使用 Secret(示例为secretName: shhh,应替换为 playbook 创建的tls-secret)承载证书,实现 HTTPS; - 路由规则:
host: hello-world.app+path: /将域名请求转发至后端 Servicehello-world的 80 端口; - 注解约定:
nginx.ingress.kubernetes.io/rewrite-target: /处理路径重写,kubernetes.io/ingress.class: nginx指定 nginx Ingress Controller(cert-manager.io/cluster-issuer注解在启用 cert-manager 时生效;本练习使用 playbook 自签证书方案,可视为可选的自动化证书替代路径)。
八、运行管道与验证
按解决方案 topics/cicd/solutions/deploy_to_kubernetes/README.md 的步骤 8-9:
- 将 Jenkinsfile 配置为 Jenkins Pipeline 任务(SCM 指向 Web 应用仓库),触发运行;
- 观察四个阶段依次通过:Checkout Source → Build image → Push image → Deploy App;
- 集群侧验证:
# 检查 Pod、Service、Ingress 状态 kubectl get deploy,svc,ing -n default # 验证 Deployment 使用了最新镜像 kubectl get deploy hello-blue-whale -o jsonpath='{.spec.template.spec.containers[0].image}' # 本地模拟域名解析后以 HTTPS 访问(自签名证书需忽略校验) curl -k https://hello-world.app预期输出为Hello World :)页面。若 HTTPS 访问失败,优先检查 IngresssecretName是否与 playbook 创建的 Secret 名称一致,以及 Ingress Controller 是否已就绪。
九、进阶变体与最佳实践
- 替换 CI/CD 平台:题目允许"任意 CI/CD 系统"。以 GitHub Actions 为例,可将四个阶段映射为 workflow 的四个 job/step(checkout →
docker build→docker push→ 调用 Ansible),核心是保持"源码 → 镜像 → 仓库 → 集群"的链路不变(仓库 topics/cicd/README.md 提供了 GitHub Actions 的 Workflow/Job/Action 概念对照,以及"提交即触发、镜像入库后集群应用变更"的 CI/CD 流程描述); - 镜像版本追踪:始终为每次构建保留
${env.BUILD_ID}唯一 tag,不要只依赖latest;回滚时只需把 Deployment 的image字段改回历史 tag 并重新 apply; - 管道幂等性:参照 playbook 的
failed_when: result.rc == 2处理"已存在"类错误,使重复执行不中断; - 证书策略:生产环境建议以 cert-manager + 受信 CA 替代自签名证书;练习中 Ingress 注解已预留
cert-manager.io/cluster-issuer的扩展位; - 分离原则:坚持 CI/CD 系统与集群分离部署,镜像通过 Registry 中转,这正是本练习要验证的工程形态。
十、小结
围绕 topics/pipeline_deploy_image_to_k8.md 这道练习题,仓库给出了从 Jenkinsfile 到 Ansible playbook、再到 Kubernetes 清单的完整可运行参考(topics/cicd/solutions/deploy_to_kubernetes/)。掌握这条链路的核心在于理解四个环节的职责边界:Jenkins 负责"构建与推送"、Registry 负责"镜像中转"、Ansible 负责"证书与资源下发"、Kubernetes 负责"运行与 HTTPS 暴露"。把这一模式固化到你的 CI/CD 体系中,即可在任意平台复现"一次提交 → 镜像上集群"的自动化发布能力。
- 文档
- 教程
- DevOps
- 运维
【免费下载链接】devops-exercises
Linux, Jenkins, AWS, SRE, Prometheus, Docker, Python, Ansible, Git, Kubernetes, Terraform, OpenStack, SQL, NoSQL, Azure, GCP, DNS, Elastic, Network, Virtualization. DevOps Interview Questions
相关推荐
Minikube 本地 Kubernetes 集群实战:从环境安装、镜像构建到应用部署(DevOps-Guide)
Minikube 本地 Kubernetes 集群实战:从环境安装、镜像构建到应用部署(DevOps Guide) 本指南以 DevOps Guide 仓库中的
云原生CI/CD运维devops-exercises 实战:使用 ArgoCD 检测并同步 Kubernetes 集群状态漂移(Sync App - Cluster)
devops exercises 实战:使用 ArgoCD 检测并同步 Kubernetes 集群状态漂移(Sync App Cluster) 导读 本指南围绕
文档教程DevOps运维ELMoForManyLangs架构解析:从CNN到双向LSTM的深度探索
ELMoForManyLangs架构解析:从CNN到双向LSTM的深度探索 ELMoForManyLangs是一个多语言预训练模型,它采用了从CNN到双向LST
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考