Docker是什么?K8s是什么?如何从0到1实现Docker与K8s全流程部署
wptr33 2025-01-09 16:35 14 浏览
云原生时代,作为技术人员,如果不了解 Docker 和 Kubernetes(K8s),那绝对是技术栈上的一个短板。那么,什么是 Docker?什么又是 Kubernetes?它们之间存在怎样的关系? 这篇文章,我将通过理论加代码实战的方式,详细地剖析他们。
1. 原理部分
1.1 Docker
Docker是一个容器化平台,它允许开发者将应用及其依赖项打包到一个称为容器的标准化单元中,以便可以在不同环境中快速、可靠地运行这些应用。它的本质是利用操作系统的Cgroups和Namespace机制创建出来的隔离环境。
Docker核心概念包括以下几个:
1.1.1 Docker核心概念
1. 镜像:Docker(Image)镜像是一个轻量级、独立、可执行的软件包,其中包含运行某个应用程序所需的所有内容,包括代码、运行时、库、环境变量和配置文件。镜像是不可变的,基于镜像可以创建容器。
2. 容器:容器(Container)是镜像的运行实例,它是一个轻量级、独立的环境,可以在任何支持 Docker的机器上运行。容器与主机系统共享操作系统内核,但在进程空间上是隔离的。
3. Dockerfile:Dockerfile是一个文本文件,包含构建 Docker镜像的所有命令,可以通过 Dockerfile来自动化镜像的创建过程。
4. Docker Hub:Docker Hub是一个云端的 Docker镜像存储库,用户可以在上面发布和获取镜像,它提供了一个平台来共享和管理镜像。
5. 容器编排:Docker Compose是一种定义和运行多容器 Docker应用程序的工具,通过一个docker-compose.yml文件,用户可以定义一个应用包含的所有服务,并使用简单的命令启动或停止它们。
Docker容器可以描述成以下全景图(图片来自极客张磊):
1.1.2 Docker的优点
Docker的优点可以用一句话总结:一次打包,到处部署。这个和 JVM一次编译,到处运行的设计有着异曲同工之妙,所以说,计算机领域很多思维是相通的!
下图对比了使用与不使用 Docker的场景:
- 不使用 Docker:每次将应用部署新主机时,都需要重新安装一遍应用需要的环境,因为操作系统多,运营商可能也不同,安装环境是一件痛苦的事情。
- 使用 Docker:制作 Docker镜像时,已经包含应用及其所需的环境,因此可以到任何运营商提供的操作系统上运行。
1.2 Kubernetes
Kubernetes(K8s) 一词源自希腊,意为“舵手”或“掌舵者”,用于指导和管理船只的航行。它是一个容器编排平台,负责自动化容器的部署、扩展(水平扩展)、负载均衡、以及故障恢复等工作。
Kubernetes的核心概念包括以下几个:
1.2.1 Kubernetes核心概念
1. 节点:节点(Node)是 Kubernetes集群中的一台物理机或虚拟机,负责运行应用程序的工作负载。每个节点运行一个Kubelet(用于管理节点上的容器)和一个容器运行时(例如Docker)。
2. Pod:Pod是 Kubernetes中最小的可部署单元,通常包含一个或多个容器。Pod中的容器共享网络和存储,可以协同工作。
3. 控制器:控制器(Controller)负责管理和维护集群中的Pod和相关的服务。常见的控制器有 ReplicaSet(确保指定数量的Pod副本在运行)、Deployment(管理无状态应用)和 StatefulSet(管理有状态应用)。
4. 服务:服务(Service)是一个抽象的方式,用于定义一组Pod的逻辑集合以及访问这些 Pod的策略。Kubernetes中的服务提供了负载均衡和服务发现功能。
5. 命名空间:命名空间(Namespace)用于在同一个 Kubernetes集群中将资源进行逻辑上的隔离。它允许多个团队或项目共享一个集群而不会相互影响。
6. 配置管理:配置管理包含 ConfigMap 和 Secret。ConfigMap 用于存储非机密的数据,类似配置文件。Secret用于存储机密数据,如密码、OAuth令牌和SSH密钥。
7. Ingress:Ingress是一个 API对象,管理外部访问到集群中服务的 HTTP和 HTTPS路由。它提供负载均衡、SSL终止和基于名称的虚拟托管等功能。
8. Deployment:Deployment是一个用于管理无状态应用程序的核心组件。它提供了一种声明式的方法来管理 Pod和 ReplicaSet,从而实现应用程序的部署、升级和扩缩。
Kubernetes可以描述成以下全景图(图片来自极客张磊):
1.2.2 Kubernetes 的工作流程
Kubernetes 的整体工作流程可以总结成下面 6个步骤:
- 用户定义和提交文件:用户通过 kubectl提交描述文件,例如 Deployment 和 Service 定义,这些文件描述了应用副本数量、负责选择负载均衡的标签、资源需求等信息。
- API Server 接受请求:API Server处理用户的对象创建请求,这些请求会被记录在 etcd 中。
- 调度器决定 Pod 的位置:Scheduler根据集群的整体资源使用情况、节点健康状况、Pod 的资源要求等调度策略,将 Pod安排到集群中的某个 Node上。
- Kubelet 处理并运行Pod:在选定的 Node上,Kubelet调用 Container Runtime(例如 Docker 或 Container)启动容器,并根据请求的规格拉取镜像、分配资源、启动应用。
- Kube Proxy 实现服务访问:集群中的 Kube Proxy负责为每个 Pod生成虚拟 IP,通过这些 IP,集群内外部的访问可以通过 Kubernetes Services 来访问这些 Pod,进行负载均衡。
- 状态保持和自动修复:Kubernetes的控制器会持续监控 Pod和节点的状态,并在检测到某些 Pod不可用或节点失效时,自动重启或调度新的 Pod到健康的节点上。
整个流程如下图:
1.3 两者关系
Docker提供容器化机制,用于封装和打包应用,并利用 CI/CD管道将容器镜像推送至中央容器注册中心(如 Docker Hub 或 Harbor),而 Kubernetes是一个强大的容器编排平台,负责调度、扩展和管理 Docker容器化应用,保证系统高可用、故障自动恢复。
从宏观上看,两者关系可以通过下图来形象的表达:
好了,理论部分讲解完后,我们正式进入代码实战部分,俗话说:说起来容易做起来难,对于 Kubernetes集群还真有点难度,来,上干货!!!
2. 代码实战
2.1 目的
开发一个简单的 Java Web应用,并将其 Docker容器化部署到 Kubernetes集群中,然后在浏览器访问,展示:Hello world, This is my docker running in Kubernetes!。
实战部分基于: Apple M1 Pro电脑
2.2 步骤
整体流程核心步骤有下面 4个:
- 安装环境
- 创建 Web应用
- 应用 Docker 容器化
- 部署到 Kubernetes 集群
- 浏览器验证
2.2.1 安装环境
首先,需要确保我们安装了以下环境:JDK(Java Development Kit), Gradle(Maven),Docker, Kubernetes,下面是我安装的版本:
JDK 版本:
Gradle版本:
Docker 版本: 直接使用 Mac brew安装:
brew install --cask docker
Kubernetes 版本:
直接使用 Mac brew安装:
brew install kubectl
注意:Gradle 和 Maven 是项目管理工具,只要安装一个就OK,自己熟悉哪个就安装哪个。
2.2.2 创建Java Web应用
1. 创建Gradle(Maven)项目
创建一个 Springboot 项目,整个目录结构如下:
在src/main/cloud/com/yuanjava/docker目录下创建一个新的 Java类,如HelloController.java:
package com.yuanjava.docker;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 猿java
*/
@RestController
public class HelloController {
@GetMapping("/test")
public String test() {
return "Hello world, This is my docker running in Kubernetes!";
}
}
2. Gradle(Maven)打包项目:
Gradle打包指令如下:
gradle build
这里在 build/libs 目录下就就会看到打包后的 jar包:
2.2.3 容器化 Java Web应用
1. 编写Dockerfile:
在项目根目录下创建一个Dockerfile:
FROM openjdk:17-jdk-slim
COPY build/libs/yuanjava-1.0.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
2. 构建Docker镜像:
在当前目录,运行以下命令就可以构建 Docker镜像,-t的作用是给这个镜像加一个Tag,也就是起一个好听的名字。
docker build -t yuanjava:1.0 .
运行完上面的指令之后,就可以在 Docker镜像库看到刚才打的镜像了,可以使用docker images指令查看镜像:
docker images
也可以通过 Docker的可视化工具查看镜像:
3. 运行Docker容器
我们可以通过下面的命令来启动 Docker容器:
docker run -p 9999:9999 yuanjava:1.0
然后,在浏览器中访问http://localhost:9999/test来测试 Docker是否启动完成。访问结果如下图:
4. 推送 Docker镜像到远程仓库
这一步是为了下面将 Docker镜像部署到 Kubernetes集群做准备,推送命令如下:
docker push yuanjava:1.0
推送完之后,远程仓库就多了一个镜像,如下图所示:
注意:如果没有 Docker账号,需要先创建账号。
2.2.4 部署到Kubernetes集群
1. 启动 Kubernetes集群
通常来说,我们会使用minikube命令来启动和管理 Kubernetes 集群,安装和启动命令如下:
# 安装 minikube
curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
chmod +x minikube
sudo mv minikube /usr/local/bin/
# 启动 Kubernetes集群
minikube start
2. 编写Kubernetes Deployment配置
创建一个deployment.yaml文件,内容如下:
apiVersion: apps/v1 # 定义了 Kubernetes API 的版本
kind: Deployment # 声明这个 Kubernetes 资源的类型
metadata:
name: yuanjava # 包含资源的元数据,Kubernetes 通过 metadata 字段中的各类信息来跟踪和管理资源
spec:
replicas: 2 # Pod的副本数量,即 Deployment将运行 2个相同的 Pod
selector:
matchLabels:
app: yuanjava # 告诉 Deployment 如何找到它管理的 Pod
template:
metadata:
labels:
app: yuanjava # 定义 Pod 的模板
spec:
containers:
- name: yuanjava
image: yuanjava/yuanjava:1.0 #定义容器使用的镜像,Kubernetes 会从容器镜像仓库中拉取它
ports:
- containerPort: 9999 # 指定容器内部监听的应用端口
3. 编写Kubernetes Service配置
创建一个service.yaml文件,内容如下:
apiVersion: v1
kind: Service # 用于描述和管理向外部或者内部暴露应用的网络访问方式
metadata:
name: yuanjava # 包含资源的元数据信息
spec:
type: LoadBalancer # 定义了服务的类型,LoadBalancer 类型会将服务暴露给外部网络
ports:
- port: 80 # 这是对外暴露的端口,表示外部客户端访问服务时使用的端口号
targetPort: 9999 # 这是集群内部目标 Pod 上运行的容器所监听的端口
selector:
app: yuanjava
4. 部署到Kubernetes
我们可以使用kubectl命令应用配置,命令说明如下:
kubectl apply -f deployment.yaml:根据 deployment.yaml 文件中的定义,创建或更新 Kubernetes中相应的 Deployment。 kubectl apply -f service.yaml:根据 service.yaml 文件中的内容,Kubernetes会创建一个 Service,并将其与运行 Deployment 中的 Pod关联起来。
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
5. 验证部署
使用以下命令检查 Pods和 Service状态:
kubectl get pods
kubectl get services
如下图,2个 Pod都处于 Running 状态:
2.2.5 浏览器验证
最后,我们可以在浏览器中访问,验证应用是否成功部署到 Kubernetes 集群,访问地址是:http://EXTERNAL-IP/hello ,如下图:
因为,我是本地部署,所以EXTERNAL-IP地址为<pending>,即未分配,但是可以通过minikube service yuanjava查看 IP地址,如下图所示:
最后,打开地址http://192.168.49.2:63213/test, 见证奇迹的时刻到了:
因为是本地环境,所以链接最终会跳转到http://127.0.0.1:63213/test 。
到此,我们就成功地手动将 Docker镜像部署到 Kubernetes集群,并且通过 URL能够访问,过程很艰辛,结果还是比较美好。
但是,如果要部署大量的机器,这样手动操作肯定是不行,因此,我们需要结组一些 CI/CD工具(如 GitHub Actions、GitLab CI/CD 或 Jenkins)实现自动化 Docker镜像构建和 Kubernetes 部署。
这里以 GitHub Actions为例,创建 .github/workflows/auto-deploy.yaml:
name: Auto Deploy Application to Kubernetes
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# Step 1: 检出代码
- name: Checkout code
uses: actions/checkout@v3
# Step 2: 登录 Docker Registry
- name: Log in to Docker Hub
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
# Step 3: 构建并推送 Docker 镜像
- name: Build and push Docker image
run: |
docker build -t ${{ secrets.DOCKER_USERNAME }}/yuanjava:latest .
docker push ${{ secrets.DOCKER_USERNAME }}/yuanjava:latest
# Step 4: 设置 kubectl
- name: Set up kubectl
uses: azure/setup-kubectl@v3
with:
version: 'latest'
# Step 5: 配置 kubeconfig 文件
- name: Configure kubeconfig
run: |
echo "${{ secrets.KUBECONFIG }}" > kubeconfig
export KUBECONFIG=kubeconfig
# Step 6: 部署到 Kubernetes
- name: Apply Kubernetes manifests
run: |
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
关键说明:
- 配置里面的 DOCKER_USERNAME, DOCKER_PASSWORD, KUBECONFIG,需在项目的 Settings > Secrets 中配置。
- 在触发阶段(push 到 main 分支)时,上述流水线将自动完成 Docker 构建、推送,并将应用部署到 Kubernetes。
3. 总结
本文,我们先从理论上分析了 Docker 和 Kubernetes的核心概念以及它们之间的关系。
接着,我们从代码实战的角度,带大家一步一步实操了如何编写一个简单的 Java Web应用,并将其 Docker容器化,最后部署到 Kubernetes集群中,然后在浏览器访问。在实操的期间,因为所有的环境都是本地环境临时搭建,所以遇到了很多的问题,但最终还是成功了。
通过这次实操,再次说明了做技术不能只停留在理论,实操很重要,实操期间我们可能遇到很多问题,但是,当我们通过各种方式去解决问题的时候,这个过程其实就是对技术更深入的学习和掌握。
个人建议:
Docker是云原生很重要相对简单的一个技术基础,强烈建议掌握并且一定要去实战。Kubernetes的难度系统会比 Docker大,它为大量容器提供调度、资源管理、弹性伸缩等功能,如果使用的机器数量比较少,Kubernetes其实很难用上,但是,如果可以,还是建议我们创造条件在实际生产环境中去使用和学习 Kubernetes。相信我,这种有压力的学习效果贼棒!
4. 参考资料
kubernetes官网
docker官网
学习交流
最后,把我的座右铭送给你:投资自己才是最大的财富。 如果你觉得本文章对你有帮助,点赞,收藏不迷路
公众号:我不是架构师,持续为你输出更多的硬核文章和面试经验。
相关推荐
- 【推荐】一款开源免费、美观实用的后台管理系统模版
-
如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!项目介绍...
- Android架构组件-App架构指南,你还不收藏嘛
-
本指南适用于那些已经拥有开发Android应用基础知识的开发人员,现在想了解能够开发出更加健壮、优质的应用程序架构。首先需要说明的是:AndroidArchitectureComponents翻...
- 高德地图经纬度坐标批量拾取(高德地图批量查询经纬度)
-
使用方法在桌面上新建一个index.txt文件,把下面的代码复制进去保存,再把文件名改成index.html保存,双击运行打开即可...
- flutter系列之:UI layout简介(flutter ui设计)
-
简介对于一个前端框架来说,除了各个组件之外,最重要的就是将这些组件进行连接的布局了。布局的英文名叫做layout,就是用来描述如何将组件进行摆放的一个约束。...
- Android开发基础入门(一):UI与基础控件
-
Android基础入门前言:...
- iOS的布局体系-流式布局MyFlowLayout
-
iOS布局体系的概览在我的CSDN博客中的几篇文章分别介绍MyLayout布局体系中的视图从一个方向依次排列的线性布局(MyLinearLayout)、视图层叠且停靠于父布局视图某个位置的框架布局(M...
- TDesign企业级开源设计系统越发成熟稳定,支持 Vue3 / 小程序
-
TDesing发展越来越好了,出了好几套组件库,很成熟稳定了,新项目完全可以考虑使用。...
- WinForm实现窗体自适应缩放(winform窗口缩放)
-
众所周知,...
- winform项目——仿QQ即时通讯程序03:搭建登录界面
-
上两篇文章已经对CIM仿QQ即时通讯项目进行了需求分析和数据库设计。winform项目——仿QQ即时通讯程序01:原理及项目分析...
- App自动化测试|原生app元素定位方法
-
元素定位方法介绍及应用Appium方法定位原生app元素...
- 61.C# TableLayoutPanel控件(c# tabcontrol)
-
摘要TableLayoutPanel在网格中排列内容,提供类似于HTML元素的功能。TableLayoutPanel控件允许你将控件放在网格布局中,而无需精确指定每个控件的位置。其单元格...
- 12个python数据处理常用内置函数(python 的内置函数)
-
在python数据分析中,经常需要对字符串进行各种处理,例如拼接字符串、检索字符串等。下面我将对python中常用的内置字符串操作函数进行介绍。1.计算字符串的长度-len()函数str1='我爱py...
- 如何用Python程序将几十个PDF文件合并成一个PDF?其实只要这四步
-
假定你有一个很无聊的任务,需要将几十个PDF文件合并成一个PDF文件。每一个文件都有一个封面作为第一页,但你不希望合并后的文件中重复出现这些封面。即使有许多免费的程序可以合并PDF,很多也只是简单的将...
- Python入门知识点总结,Python三大数据类型、数据结构、控制流
-
Python基础的重要性不言而喻,是每一个入门Python学习者所必备的知识点,作为Python入门,这部分知识点显得很庞杂,内容分支很多,大部分同学在刚刚学习时一头雾水。...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
因果推断Matching方式实现代码 因果推断模型
-
面试官:git pull是哪两个指令的组合?
-
git pull命令使用实例 git pull--rebase
-
git 执行pull错误如何撤销 git pull fail
-
git pull 和git fetch 命令分别有什么作用?二者有什么区别?
-
git fetch 和git pull 的异同 git中fetch和pull的区别
-
git pull 之后本地代码被覆盖 解决方案
-
还可以这样玩?Git基本原理及各种骚操作,涨知识了
-
git命令之pull git.pull
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mysql max (33)
- vba instr (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)