首页
恋爱日记
数据统计
留言板
更多
友情链接
Search
1
CentOS7安装部署weblogic12.1.1
3,130 阅读
2
Docker真的被Kubernetes放弃了吗?
2,824 阅读
3
一款可以自定义VScode背景的插件
2,682 阅读
4
Nginx搭建本地YUM仓库
2,352 阅读
5
CentOS 7安装fail2ban+Firewalld防止SSH爆破与CC攻击
2,157 阅读
Prometheus网站监控面板
Vscode
Typecho优化
Ops工具
Linux
Shell
Nginx
Weblogic
云原生
Kubernetes
Docker
Ceph
监控
Promethues
Zabbix
Grafana
数据库
MySQL
登录
Search
废柴阿尤
累计撰写
25
篇文章
累计收到
14
条评论
首页
栏目
Prometheus网站监控面板
Vscode
Typecho优化
Ops工具
Linux
Shell
Nginx
Weblogic
云原生
Kubernetes
Docker
Ceph
监控
Promethues
Zabbix
Grafana
数据库
MySQL
页面
恋爱日记
数据统计
留言板
友情链接
搜索到
5
篇与
的结果
2024-01-07
Docker真的被Kubernetes放弃了吗?
首先,要明确的是,Kubernetes 并没有完全放弃 Docker,而是改变了对 Docker 的使用方式。 这一改变主要是因为 Kubernetes 1.20 版本开始,宣布弃用了 Docker 作为容器运行时的支持(Dockershim 的移除)。这意味着,虽然在 Kubernetes 集群中可以运行用 Docker 构建的容器镜像,但 Kubernetes 将不再使用 Docker 作为容器运行时。1、Docker 是什么? ::(疑问) Docker 是一个开源的应用容器引擎,它允许开发者打包他们的应用及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙盒机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。 Docker 使用的是客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。Docker 容器通过 Docker 镜像来创建。镜像可以看作是容器的“模版”,而容器则是这些模版的实例化对象。Docker 提供了一个非常便捷的镜像使用方式,除了可以使用本地镜像外,还可以从 Docker Hub 上下载数以万计的镜像使用。2、Kubernetes 是什么? ::(疑问) Kubernetes(也称为 K8s)是用于自动部署、扩展和管理容器化应用程序的开源系统。它由 Google 设计并捐赠给 Cloud Native Computing Foundation 来维护。Kubernetes 提供了一个用于部署应用程序的框架,支持应用程序的扩展和故障处理等功能,还提供了一系列的工具和服务以实现各种需求。Kubernetes 的核心功能包括自动化容器的部署和复制随时扩展或缩减容器数量将容器组织成组并提供容器间的负载均衡服务发现和负载均衡自动挂载存储系统自动化的滚动更新自我修复,如重新启动失败的容器3、Docker 和 Kubernetes 的区别? ::(冷) 虽然 Docker 和 Kubernetes 都是与容器化技术相关的工具,但它们在某些方面有着明显的不同。 使用范围和目的: Docker 主要关注的是容器的打包和运行,简化了应用程序的交付。而 Kubernetes 更加关注的是容器的协调和管理,包括自动部署、扩展、运行和调度容器。 设计和架构: Docker 使用简单的设计,易于理解和使用。它可以在单机上运行,也可以结合 Docker Swarm 在多机上协同工作。Kubernetes 则更加复杂,提供更多的功能和更高的灵活性,它是为在集群上大规模运行和管理容器化应用设计的。 功能和特性: Docker 直接处理容器的创建和运行,而 Kubernetes 提供了更复杂的调度器和集群管理工具。Kubernetes 能够管理和调度多个容器组成的应用,具有自动扩展、自愈等高级特性。 生态系统和社区: 虽然 Docker 和 Kubernetes 都拥有强大的社区支持,但 Kubernetes 在云计算和微服务领域的生态系统更为丰富,支持更多的云平台和产品集成。 总的来说,Docker 更专注于单个容器的生命周期,而 Kubernetes 更关注容器集群的整体管理。在微服务和云原生应用的趋势下,两者往往是相辅相成的关系,Docker 用于容器化应用,而 Kubernetes 用于管理这些容器化的应用。4、Kubernetes 对 Docker 的使用方式改变 ::(你懂的) 首先,要明确的是,Kubernetes 并没有完全放弃 Docker,而是改变了对 Docker 的使用方式。这一改变主要是因为 Kubernetes 1.20 版本开始,宣布弃用了 Docker 作为容器运行时的支持(Dockershim 的移除)。这意味着,虽然在 Kubernetes 集群中可以运行用 Docker 构建的容器镜像,但 Kubernetes 将不再使用 Docker 作为容器运行时。 这个改变背后的原因是 Docker 和 Kubernetes 之间的技术差异。Docker 是一个包含多种功能的大型应用,除了容器运行时之外,还包括图像管理、存储、网络等。而 Kubernetes 实际上只需要容器运行时这一部分功能。因此,为了减轻 Kubernetes 的负担,更高效地管理容器,Kubernetes 开始支持更加轻量级和标准化的容器运行时接口(CRI)。5、Kuberetes 并没有淘汰 Docker ::(笑眼) 这并不意味着 Docker 被淘汰,因为 Docker 构建的容器镜像仍然可以在 Kubernetes 中运行。只是 Kubernetes 会使用其他容器运行时(如 containerd 或 CRI-O)来直接运行这些镜像。Docker 镜像本身符合 OCI(Open Container Initiative)标准,因此可以被任何标准的容器运行时使用。6、Docker 在 Kubernetes 生态中的角色 :@(想一想) 在这种情况下,Docker 更像是一个开发工具,而不是在生产环境中的容器运行时。开发者仍然可以使用 Docker 来构建、测试容器镜像,然后将这些镜像部署到 Kubernetes 集群中。实际上,这种变化让 Kubernetes 变得更加高效,因为它可以直接与底层容器运行时接口交互,减少了不必要的中间层。 两个代码示例来展示如何在 Kubernetes 环境中使用容器。第一个示例是一个 Dockerfile,用于创建一个简单的 Docker 镜像;第二个示例是一个 Kubernetes 的部署配置文件(Deployment)用于在 Kubernetes 集群中部署这个镜像。这两个示例将展示如何将一个 Docker 容器化的应用部署到 Kubernetes 集群中。示例 1:Dockerfile这个 Dockerfile 示例将创建一个简单的 Node.js 应用的 Docker 镜像。# 使用官方的 Node.js 基础镜像作为构建环境 FROM node:14 # 设置工作目录为 /app WORKDIR /app # 将 package.json 和 package-lock.json 复制到容器中 COPY package*.json ./ # 安装应用依赖 RUN npm install # 将应用的源代码复制到容器中 COPY . . # 应用运行时监听的端口 EXPOSE 8080 # 定义容器启动时运行的命令 CMD ["node", "server.js"] 在这个 Dockerfile 中,我们基于 Node.js 的官方镜像创建一个新的镜像,安装了应用的依赖,并设置容器启动时执行的命令。示例 2:Kubernetes Deployment 配置文件这个 YAML 文件示例定义了一个 Kubernetes Deployment,用于部署上面创建的 Docker 镜像。apiVersion: apps/v1 kind: Deployment metadata: name: nodejs-app labels: app: nodejs-app spec: replicas: 2 # 创建两个副本 selector: matchLabels: app: nodejs-app template: metadata: labels: app: nodejs-app spec: containers: - name: nodejs-container image: your-dockerhub-username/nodejs-app:latest # 指定 Docker 镜像 ports: - containerPort: 8080 # 容器应用监听的端口 在这个 YAML 文件中,我们定义了一个名为 nodejs-app 的 Deployment。它将部署两个副本的容器,每个容器都运行 your-dockerhub-username/nodejs-app:latest 镜像(这里你需要替换成你自己的 Docker Hub 用户名和镜像名)。这个部署配置指定了容器内部的应用监听端口为 8080。 结合这两个示例,你可以看到 Docker 和 Kubernetes 如何一起工作来容器化和部署一个应用。首先,使用 Docker 构建一个应用的镜像,然后通过 Kubernetes 部署配置在集群中部署这个镜像。7、总结,Docker真的被Kubernetes放弃了吗? ::(滑稽) 所以,我们可以说 Kubernetes 改变了对 Docker 的使用方式,而不是完全放弃了 Docker。这种变化更多地反映了 Kubernetes 向标准化、高效化发展的趋势,同时也保留了 Docker 在容器技术领域的核心价值和广泛使用。对于开发者来说,这意味着他们仍然可以在开发过程中使用 Docker,而 Kubernetes 则更专注于容器的编排和管理。
2024年01月07日
2,824 阅读
2 评论
1,569 点赞
2023-11-15
Kind快速部署Kubernetes多集群
Kind架构及原理 Kind 使用一个 container 来模拟一个 node,在 container 里面跑 systemd ,并用 systemd 托管 kubelet 以及 containerd,然后通过容器内部的 kubelet 把其他 K8s 组件,比如 kube-apiserver、etcd、CNI 等跑起来。它可以通过配置文件的方式创建多个 container 来模拟创建多个 node,并以这些 node 构建一个多节点的 Kubernetes 集群。Kind 内部使用的集群部署工具是 kubeadm,借助 kubeadm 提供的 Alpha 特性,它可以部署包括 HA master 的高可用集群。同时,在 HA master 下, 它还额外部署了一个 Nginx,用来提供负载均衡 vip。Docker 安装宿主机安装Dockerroot@k8s:~# for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do apt-get remove $pkg; doneroot@k8s:~# apt-get update root@k8s:~# apt-get install ca-certificates curl gnupg root@k8s:~# install -m 0755 -d /etc/apt/keyrings root@k8s:~# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg root@k8s:~# chmod a+r /etc/apt/keyrings/docker.gpg # Add the repository to Apt sources: root@k8s:~# echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null root@k8s:~# apt-get update安装Dockerroot@k8s:~# apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginKind安装首先我们下载Kind二进制包root@k8s:~# wget https://github.com/kubernetes-sigs/kind/releases/download/v0.20.0/kind-linux-amd64 root@k8s:~# mv kind-linux-amd64 /usr/bin/kind root@k8s:~# chmod +x /usr/bin/kind指定版本号并创建集群root@k8s:~# cat >kind-demo.yaml<<EOF kind: Cluster name: k8s-kind-demo apiVersion: kind.x-k8s.io/v1alpha4 networking: disableDefaultCNI: false nodes: - role: control-plane #- role: control-plane #- role: control-plane - role: worker - role: worker - role: worker EOF参数详解:name 设置集群名称networking.disableDefaultCNI 创建的集群默认自带一个轻量级的 CNI 插件 kindnetd ,我们也可以禁用默认设置来安装其他 CNI,比如 Calico。nodes control-plance master节点数量nodes worker node节点数量快速创建集群{message type="success" content="本次版本采用v1.24.15"/}root@k8s:~# kind create cluster --config=kind-demo.yaml --image=kindest/node:v1.24.15 --name=k8s-kind-demo 日志输出以下 Creating cluster "k8s-kind-demo" ... ✓ Ensuring node image (kindest/node:v1.24.15) 🖼 ✓ Preparing nodes 📦 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 ✓ Joining worker nodes 🚜 Set kubectl context to "kind-k8s-kind-demo" You can now use your cluster with: kubectl cluster-info --context kind-k8s-kind-demo Thanks for using kind! 😊安装kubectlroot@k8s:~# curl -LO https://dl.k8s.io/release/v1.24.15/bin/linux/amd64/kubectl root@k8s:~# chmod +x kubectl root@k8s:~# mv kubectl /usr/bin/可以查看集群状态root@k8s:~# kubectl cluster-info --context kind-k8s-kind-demo Kubernetes control plane is running at https://127.0.0.1:42687 CoreDNS is running at https://127.0.0.1:42687/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'接下来我们就可以get node查看到节点信息root@k8s:~# kubectl get node NAME STATUS ROLES AGE VERSION k8s-kind-demo-control-plane Ready control-plane 2m2s v1.24.15 k8s-kind-demo-worker Ready <none> 90s v1.24.15 root@k8s:~# kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE coredns-57575c5f89-9ltk6 1/1 Running 0 108s coredns-57575c5f89-glgvh 1/1 Running 0 107s etcd-k8s-kind-demo-control-plane 1/1 Running 0 2m7s kindnet-ljptz 1/1 Running 0 99s kindnet-qzglw 1/1 Running 0 109s kube-apiserver-k8s-kind-demo-control-plane 1/1 Running 0 2m5s kube-controller-manager-k8s-kind-demo-control-plane 1/1 Running 0 2m1s kube-proxy-kvzx9 1/1 Running 0 109s kube-proxy-pnzmz 1/1 Running 0 99s kube-scheduler-k8s-kind-demo-control-plane 1/1 Running 0 2m9sKind 常用命令查看集群 root@k8s:~# kind get clusters 删除集群 root@k8s:~# kind delete cluster --name 集群名称Kind创建多套集群实际上只是需要给yaml文件修改即可root@k8s:~# cat >kind-demo1.yaml<<EOF kind: Cluster name: k8s-kind-demo1 apiVersion: kind.x-k8s.io/v1alpha4 networking: disableDefaultCNI: true #这里开启个cni nodes: - role: control-plane #- role: control-plane #- role: control-plane - role: worker EOF{alert type="success"}disableDefaultCNI禁用了默认的kindnetd插件,CNI就需要我们自己安装flannel或者其它calico组件{/alert}使用下面命令创建集群{message type="success" content="版本我们换成1.28.0"/}root@k8s:~# kind create cluster --config=kind-demo1.yaml --image=kindest/node:v1.28.0 --name=k8s-kind-demo1 日志 输出如下 Creating cluster "k8s-kind-demo1" ... ✓ Ensuring node image (kindest/node:v1.28.0) 🖼 ✓ Preparing nodes 📦 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing StorageClass 💾 ✓ Joining worker nodes 🚜 Set kubectl context to "kind-k8s-kind-demo1" You can now use your cluster with: kubectl cluster-info --context kind-k8s-kind-demo1 Thanks for using kind! 😊查看集群状态root@k8s:~# kubectl get node NAME STATUS ROLES AGE VERSION k8s-kind-demo1-control-plane NotReady control-plane 3m46s v1.28.0 k8s-kind-demo1-worker NotReady <none> 3m17s v1.28.0 pod状态 root@k8s:~# kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE coredns-5dd5756b68-l94jm 0/1 Pending 0 3m58s coredns-5dd5756b68-psm7p 0/1 Pending 0 3m58s etcd-k8s-kind-demo1-control-plane 1/1 Running 0 4m12s kube-apiserver-k8s-kind-demo1-control-plane 1/1 Running 0 4m11s kube-controller-manager-k8s-kind-demo1-control-plane 1/1 Running 0 4m12s kube-proxy-bln4n 1/1 Running 0 3m50s kube-proxy-l4k49 1/1 Running 0 3m59s kube-scheduler-k8s-kind-demo1-control-plane 1/1 Running 0 4m16s{message type="success" content="切换集群"/}1.24集群版本默认cni插件1.28集群版本不使用默认插件接下来可以通过kubectl config use-context xx_name快速切换集群首先获取Cluster名称,我现在在k8s 1.28版本,现在我切换到1.24.15版本root@k8s:~# kind get clusters k8s-kind-demo k8s-kind-demo1切换到k8s-kind-demo集群root@k8s:~# kubectl config use-context kind-k8s-kind-demo Switched to context "kind-ak8s-kind-demo". root@k8s:~# kubectl get node NAME STATUS ROLES AGE VERSION k8s-kind-demo-control-plane Ready control-plane 43m v1.24.15 k8s-kind-demo-worker Ready <none> 43m v1.24.15切换到k8s-kind-demo1集群root@k8s:~# kubectl config use-context kind-k8s-kind-demo1 Switched to context "kind-k8s-kind-demo1". root@k8s:~# kubectl get node NAME STATUS ROLES AGE VERSION k8s-kind-demo1-control-plane NotReady control-plane 36m v1.28.0 k8s-kind-demo1-worker NotReady <none> 36m v1.28.0测试集群root@k8s:~# cat<<EOF | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: nginx:alpine name: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx spec: selector: app: nginx type: NodePort ports: - protocol: TCP port: 80 targetPort: 80 nodePort: 30001 --- apiVersion: v1 kind: Pod metadata: name: busybox namespace: default spec: containers: - name: busybox image: centos:v1 command: - sleep - "3600" imagePullPolicy: IfNotPresent restartPolicy: Always EOF查看服务状态root@k8s:~# kubectl get pod,svc NAME READY STATUS RESTARTS AGE pod/busybox 1/1 Running 0 2m27s pod/nginx-6fb79bc456-st6qk 1/1 Running 0 2m27s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 48m service/nginx NodePort 10.96.93.229 <none> 80:30001/TCP 2m28s测试dnsroot@k8s:~# kubectl exec -ti busybox -- nslookup kubernetes Server: 10.96.0.10 Address: 10.96.0.10#53 Name: kubernetes.default.svc.cluster.local Address: 10.96.0.1测试nginx nodeport{alert type="success"}nginx nodeport>nginx需要进入到node容器{/alert}root@k8s:~# kubectl get node NAME STATUS ROLES AGE VERSION k8s-kind-demo-control-plane Ready control-plane 53m v1.24.15 k8s-kind-demo-worker Ready <none> 52m v1.24.15 root@k8s:~# docker exec -it k8s-kind-demo-control-plane bash root@k8s-kind-demo-control-plane:/#访问nginxroot@k8s:~# curl 10.96.93.229
2023年11月15日
2,027 阅读
0 评论
352 点赞
2022-05-08
此内容被密码保护
加密文章,请前往内页查看详情
2022年05月08日
1,867 阅读
0 评论
1,162 点赞
2021-12-19
Kubernetes Pod与宿主机时区不同步
{alert type="error"}在安装Kubernetes集群的过程中并没有注意到pod的时间问题,直到在Tomcat上部署应用后发现pod中的时间与Node上的时间不同步。针对时区不同文章有以下解决方案{/alert}问题在Kubernetes集群中运行的容器默认会使用UTC时间,即北京时间为凌晨3点时,容器时间为晚上7点,中间会有8小时时差。而有些分布式系统对于时间极为敏感,不允许出现时间误差这里我们构建一个Nginx镜像,查看构建前的时间apiVersion: v1 kind: Pod metadata: name: time-nginx spec: containers: - name: time-nginx image: nginx args: [/bin/sh, -c, 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']创建完Pod后我们查看一下时间[root@k8s-01 test]# kubectl logs -f time 337: Fri Dec 1 19:01:30 UTC 2021 338: Fri Dec 1 19:01:31 UTC 2021 339: Fri Dec 1 19:01:32 UTC 2021 340: Fri Dec 1 19:01:33 UTC 2021 341: Fri Dec 1 19:01:34 UTC 2021 342: Fri Dec 1 19:01:35 UTC 2021查看一下宿主机时间[root@k8s-01 ~]# date Wed Dec 15 00:00:51 CST 2021解决首先要确保宿主机时间同步timedatectl set-timezone Asia/Shanghai #将当前的 UTC 时间写入硬件时钟 timedatectl set-local-rtc 0 #重启依赖于系统时间的服务 systemctl restart rsyslog systemctl restart crond目前解决Pod和宿主机时间不一致有以下集中解决方案通过定制Dockerfile添加时区通过将时区文件挂在到Pod中通过环境变量定义时区进入容器内修改时区网上资料还有通过PodPreset的方式,但是我测试完毕之后没有效果~ 这里就不进行整理了通过定制Dockerfile添加时区$ cat Dockerfile.date FROM centos RUN rm -f /etc/localtime \ && ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone # 构建容器镜像 $ docker build -t centos7-date:test -f Dockerfile.date . Sending build context to Docker daemon 4.426GB Step 1/2 : FROM centos ---> 1e1148e4cc2c Step 2/2 : RUN rm -f /etc/localtime && ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone ---> Running in fe2e931c3cf2 '/etc/localtime' -> '/usr/share/zoneinfo/Asia/Shanghai' Removing intermediate container fe2e931c3cf2 ---> 2120143141c8 Successfully built 2120143141c8 Successfully tagged centos7-date:test $ docker run -it centos7-date:test /bin/sh sh-4.2# date Wed Dec 6 16:40:01 CST 2021通过将时区文件挂在到Pod中[root@k8s-01 test]# cat time-mount.yaml apiVersion: v1 kind: Pod metadata: name: time spec: containers: - name: time image: nginx args: [/bin/sh, -c, 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done'] volumeMounts: - name: timezone mountPath: /etc/localtime volumes: - name: timezone hostPath: path: /usr/share/zoneinfo/Asia/Shanghai我们可以通过命令查看,/etc/localtime的目录实际上就是个软连接如果需要系统修改时区,那么只需要将时区文件覆盖到/etc/localtime,前提是我们设置好上海的时区。[root@k8s-01 test]# ll /etc/localtime lrwxrwxrwx. 1 root root 35 Apr 20 00:11 /etc/localtime -> ../usr/share/zoneinfo/Asia/Shanghai通过环境变量定义时区[root@k8s-01 test]# cat time.yaml apiVersion: v1 kind: Pod metadata: name: time-nginx spec: containers: - name: time-nginx image: nginx args: [/bin/sh, -c, 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done'] env: - name: TZ value: Asia/Shanghai
2021年12月19日
1,837 阅读
0 评论
635 点赞
2020-09-15
Docker镜像构建知识:Dockerfile 命令详解
本篇介绍了 Dockerfile 典型的基本结构和它支持的众多指令,并具体讲解通过这些指令来编写定制镜像的 Dockerfile,以及如何生成镜像。1.FROM指定基础镜像FROM 指令用于指定其后构建新镜像所使用的基础镜像。如果本地不存在,则默认会去Docker Hub下载指定镜像。FROM指令必是Dockerfile文件中的首条命令,启动构建流程后,Docker将基于该镜像构建新镜像,FROM后的命令也会基于这个基础镜像。FROM 语法格式为: FROM <image>或 FROM <image>:<tag>或 FROM <image>:<digest>通过FROM指定的镜像,可以是任何有效的基础镜像。FROM有以下限制:FROM必须是Dockerfile中第一条非注释命令在一个Dockerfile文件中创建多个镜像时,FROM可以多次出现。只需在每个新命令FROM之前,记录提交上次的镜像 ID。tag 或digest是可选的,如果不使用这两个值时,会使用ltest版本的基础镜像2.RUN执行命令在镜像的构建过程中执行特定的命令,并生成一个中间镜像。格式:#shell格式 RUN <command> #exec格式 RUN ["executable", "param1", "param2"]RUN命令将在当前image中执行任意合法命令并提交执行结果。命令执行提交后,就会自动执行Dockerfile中的下一个指令。层级 RUN指令和生成提交是符合Docker核心理念的做法。它允许像版本控制那样,在任意一个点,对image镜像进行定制化构建。RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache。{message type="error" content="每条RUN指令将在当前镜像的基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用\来换行。"/}3.CMD启动容器CMD 用于指定在容器启动时所要执行的命令。CMD 有以下三种格式:CMD ["executable","param1","param2"] CMD ["param1","param2"] CMD command param1 param2省略可执行文件的exec格式,这种写法使CMD中的参数当做ENTRYPOINT的默认参数,此时ENTRYPOINT也应该是exec格式,具体与ENTRYPOINT的组合使用,参考ENTRYPOINT。{alert type="error"}注意:与 RUN 指令的区别:RUN 在构建的时候执行,并生成一个新的镜像,CMD 在容器运行的时候执行,在构建时不进行任何操作。{/alert}{message type="error" content="每个Dockerfile只能有一条CMD命令。如果指定了多条命令,只有最后一条会被执行。如果用户启动容器时手动指定了运行的命令(作为run的参数),则会覆盖掉CMD指定的命令。"/}4.LABEL添加元数据LABEL 用于为镜像添加元数据,元数以键值对的形式指定:LABEL <key>=<value> <key>=<value> <key>=<value> ...使用 LABEL 指定元数据时,一条 LABEL 可以指定一条或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条 LABEL 指令指定,以免生成过多的中间镜像。如,通过 LABEL 指定一些元数据:LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"指定后可以通过 docker inspect 查看:docker inspect /test "Labels": { "version": "1.0", "description": "这是一个Web服务器", "by": "IT笔录" },5.EXPOSE设置监听端口为构建的镜像设置监听端口,是容器在运行时监听。格式:EXPOSE <port>[<port>...] #例如:EXPOSE 22 80 8443{alert type="error"}注意:该指令知识起到声明作用,并不会自动完成端口映射。在启动容器时需要使用-P,Docker主机会自动分配一个宿主机的临时端口转发到指定的端口;使用-p(注意大小写),则可以具体指定哪个宿主机的本地端口有会映射过来。{/alert}6.ENV设置环境变量指定环境变量,在镜像生成过程中会被后续 RUN 指令使用,在镜像启动的容器中也会存在。ENV <key> <value> ENV <key1>=<value1> <key2>=<value2>...7.COPY复制格式如下:COPY <源路径>... <目标路径> COPY ["<源路径1>",... "<目标路径>"]复制本地主机的源地址(为 Dockerfile 所在目录的相对路径、文件或目录)下的内容到镜像的目的地址下。目标路径不存在时,会自动创建。 当使用本地目录为源目录时,推荐使用COPY。8.ADD复制该命令将复制指定的源路径下的内容到容器中的目的路径下。ADD 指令和 COPY 的格式和性质基本是一致的。但是在 COPY 基础上增加了一些功能。例如源路径可以是一个 URL,这种情况下,Docker 引擎会试图去下载这个链接的文件到目标路径去。在构建镜像时,复制上下文中的文件到镜像内,格式:ADD <源路径>... <目标路径> ADD ["<源路径>",... "<目标路径>"]9.ENTRYPOINTENTRYPOINT 用于给容器配置一个可执行程序。也就是说,每次使用镜像创建容器时,通过 ENTRYPOINT 指定的程序都会被设置成默认程序。ENTRYPOINT 有以下两种形式:ENTRYPOINT ["executable", "param1", "param2"] ENTRYPOINT command param1 param2ENTRYPOINT 与 CMD 非常类似,不同的是通过docker run执行的命令不会覆盖 ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给 ENTRYPOINT。Dockerfile 中只允许有一个 ENTRYPOINT 命令,多指定时会覆盖前面的设置,而只执行最后的 ENTRYPOINT 指令。docker run运行容器时指定的参数都会被传递给 ENTRYPOINT ,且会覆盖 CMD 命令指定的参数。如,执行docker run <image> -d时,-d 参数将被传递给入口点。也可以通过docker run --entrypoint重写 ENTRYPOINT 入口点。如:可以像下面这样指定一个容器执行程序:ENTRYPOINT ["/usr/bin/nginx"]完整构建代码:FROM ubuntu:16.04 MAINTAINER MoeWah "admin@mao.sh" RUN apt-get update RUN apt-get install -y nginx RUN echo 'Hello World, 我是个容器' \ > /var/www/html/index.html ENTRYPOINT ["/usr/sbin/nginx"] EXPOSE 80使用 docker build 构建镜像,并将镜像指定为 moewah/test:docker build -t="moewah/test" .构建完成后,使用 moewah/test 启动一个容器:docker run -i -t moewah/test -g "daemon off;"在运行容器时,我们使用了-g "daemon off;",这个参数将会被传递给 ENTRYPOINT,最终在容器中执行的命令为/usr/sbin/nginx -g "daemon off;"。10.VOLUME 定义匿名卷VOLUME 用于创建挂载点,即向基于所构建镜像创始的容器添加卷:VOLUME ["/data"]一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:卷可以容器间共享和重用容器并不一定要和其它容器共享卷修改卷后会立即生效对卷的修改不会对镜像产生影响卷会一直存在,直到没有任何容器在使用它{message type="error" content="VOLUME 让我们可以将源代码、数据或其它内容添加到镜像中,而又不并提交到镜像中,并使我们可以多个容器间共享这些内容。"/}11.WORKDIR指定工作目录WORKDIR 用于在容器内设置一个工作目录:WORKDIR /path/to/workdir通过 WORKDIR 设置工作目录后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT、ADD、COPY 等命令都会在该目录下执行。 如,使用 WORKDIR 设置工作目录:WORKDIR /aWORKDIR bWORKDIR cRUN pwd在以上示例中,pwd 最终将会在/a/b/c目录中执行。在使用 docker run 运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。12.USER指定当前用户指定运行容器时的用户名或 UID,后续的 RUN 等指令也会使用指定的用户身份。语法格式为:USER daemon使用 USER 指定用户时,可以使用用户名、UID 或 GID,或者两者的组合。以下都是合法的指定:USER user USER user:group USER uid USER uid:gid USER user:gid USER uid:group13.ARG指定一些镜像内使用的参数(例如版本号信息等),这些参数在执行docker build命令时才以--build-arg<varname>=<value>格式传入。语法格式为:ARG <name>[=<default value>] docker build --build-arg site=moewah.com -t moewah/test .14.ONBUILD配置当前所创建的镜像作为其他镜像的基础镜像时,所执行的创建操作指令。语法格式为:ONBUILD [INSTRUCTION]例如,Dockerfile 使用如下的内容创建了镜像image-A:[...] ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src [...]如果基于 image-A 创建新的镜像时,新的 Dockerfile 中使用FROM image-A指定基础镜像,会自动执行 ONBUILD 指令的内容,等价于在后面添加了两条指令:FROM image-A ADD . /app/src RUN /usr/local/bin/python-build --dir /app/src使用 ONBUILD 指令的镜像,推荐在标签中注明,例如ruby:1.9-onbuild。15.STOPSIGNALSTOPSIGNAL 用于设置停止容器所要发送的系统调用信号:STOPSIGNAL signal所使用的信号必须是内核系统调用表中的合法的值,如:SIGKILL。16.SHELL指定其他命令使用 shell 时的默认 shell 类型。SHELL ["executable", "parameters"]默认值为["/bin/sh","-c"]。{message type="error" content="对于Windows系统,建议在Dockerfile开头添加# escape=来指定转移信息。"/}17.Dockerfile示例{tabs}{tabs-pane label="构建 Nginx 运行环境"}# 指定基础镜像 FROM sameersbn/ubuntu:14.04.20161014 # 维护者信息 MAINTAINER moewah "admin@mao.sh" # 设置环境 ENV RTMP_VERSION=1.1.10 \ NPS_VERSION=1.11.33.4 \ LIBAV_VERSION=11.8 \ NGINX_VERSION=1.10.1 \ NGINX_USER=www-data \ NGINX_SITECONF_DIR=/etc/nginx/sites-enabled \ NGINX_LOG_DIR=/var/log/nginx \ NGINX_TEMP_DIR=/var/lib/nginx \ NGINX_SETUP_DIR=/var/cache/nginx # 设置构建时变量,镜像建立完成后就失效 ARG BUILD_LIBAV=false ARG WITH_DEBUG=false ARG WITH_PAGESPEED=true ARG WITH_RTMP=true # 复制本地文件到容器目录中 COPY setup/ ${NGINX_SETUP_DIR}/ RUN bash ${NGINX_SETUP_DIR}/install.sh # 复制本地配置文件到容器目录中 COPY nginx.conf /etc/nginx/nginx.conf COPY entrypoint.sh /sbin/entrypoint.sh # 运行指令 RUN chmod 755 /sbin/entrypoint.sh # 允许指定的端口 EXPOSE 80/tcp 443/tcp 1935/tcp # 指定网站目录挂载点 VOLUME ["${NGINX_SITECONF_DIR}"] ENTRYPOINT ["/sbin/entrypoint.sh"] CMD ["/usr/sbin/nginx"]{/tabs-pane}{tabs-pane label="构建 Tomcat 环境"}# 指定基于的基础镜像 FROM ubuntu:13.10 # 维护者信息 MAINTAINER moewah "admin@mao.sh" # 镜像的指令操作 # 获取APT更新的资源列表 RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe"> /etc/apt/sources.list # 更新软件 RUN apt-get update # Install curl RUN apt-get -y install curl # Install JDK 7 RUN cd /tmp && curl -L 'http://download.oracle.com/otn-pub/java/jdk/7u65-b17/jdk-7u65-linux-x64.tar.gz' -H 'Cookie: oraclelicense=accept-securebackup-cookie; gpw_e24=Dockerfile' | tar -xz RUN mkdir -p /usr/lib/jvm RUN mv /tmp/jdk1.7.0_65/ /usr/lib/jvm/java-7-oracle/ # Set Oracle JDK 7 as default Java RUN update-alternatives --install /usr/bin/java java /usr/lib/jvm/java-7-oracle/bin/java 300 RUN update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/java-7-oracle/bin/javac 300 # 设置系统环境 ENV JAVA_HOME /usr/lib/jvm/java-7-oracle/ # Install tomcat7 RUN cd /tmp && curl -L 'http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.8/bin/apache-tomcat-7.0.8.tar.gz' | tar -xz RUN mv /tmp/apache-tomcat-7.0.8/ /opt/tomcat7/ ENV CATALINA_HOME /opt/tomcat7 ENV PATH $PATH:$CATALINA_HOME/bin # 复件tomcat7.sh到容器中的目录 ADD tomcat7.sh /etc/init.d/tomcat7 RUN chmod 755 /etc/init.d/tomcat7 # Expose ports. 指定暴露的端口 EXPOSE 8080 # Define default command. ENTRYPOINT service tomcat7 start && tail -f /opt/tomcat7/logs/catalina.out{/tabs-pane}{tabs-pane label="tomcat7.sh命令文件"}export JAVA_HOME=/usr/lib/jvm/java-7-oracle/ export TOMCAT_HOME=/opt/tomcat7 case $1 in start) sh $TOMCAT_HOME/bin/startup.sh ;; stop) sh $TOMCAT_HOME/bin/shutdown.sh ;; restart) sh $TOMCAT_HOME/bin/shutdown.sh sh $TOMCAT_HOME/bin/startup.sh ;; esac exit 0{/tabs-pane}{/tabs}写在最后:原则和建议首先,要尽量吃透每个指令的含义和执行效果,自己多编写一些简单的例子进行测试,弄清楚了在撰写正式的 Dockerfile。此外,Docker Hub 官方仓库中提供了大量的优秀镜像和对应的 Dockerfile,可以通过阅读它们来学习如何撰写高效的 Dockerfile。容器轻量化。从镜像中产生的容器应该尽量轻量化,能在足够短的时间内停止、销毁、重新生成并替换原来的容器。使用 .gitignore。在大部分情况下,Dockerfile 会和构建所需的文件放在同一个目录中,为了提高构建的性能,应该使用 .gitignore 来过滤掉不需要的文件和目录。为了减少镜像的大小,减少依赖,仅安装需要的软件包。一个容器只做一件事。解耦复杂的应用,分成多个容器,而不是所有东西都放在一个容器内运行。如一个 Python Web 应用,可能需要 Server、DB、Cache、MQ、Log 等几个容器。一个更加极端的说法:One process per container。减少镜像的图层。不要多个 Label、ENV 等标签。对续行的参数按照字母表排序,特别是使用apt-get install -y安装包的时候。使用构建缓存。如果不想使用缓存,可以在构建的时候使用参数--no-cache=true来强制重新生成中间镜像。
2020年09月15日
1,534 阅读
0 评论
537 点赞
首页
复制
搜索
前进
后退
重载网页
和我当邻居