第4关 K8S的旧爱Docker
docker只是容器化引擎中的一种,但由于它入行较早,在K8s刚面世的早期,docker无疑是最佳的容器运行时选择没有之一,但随着k8s的新宠Containerd逐渐成熟,并在1.24版本开始CRI默认不支持docker只支持Containerd时,docker也渐渐在走下坡路了,但不可否认的是,对现在来说,docker在容器全生命周期里面,抛开k8s不说,依然是很不错的
大家好,我是博哥爱运维,知己知彼方能百战百胜,无论是游戏还是技术都是同一个道理,docker只是容器化引擎中的一种,但由于它入行较早,在K8s刚面世的早期,docker无疑是最佳的容器运行时选择没有之一,但随着k8s的新宠Containerd逐渐成熟,并在1.24版本开始CRI默认不支持docker只支持Containerd时,docker也渐渐在走下坡路了,但不可否认的是,对现在来说,docker在容器全生命周期里面,抛开k8s不说,依然是很不错的,尤其是在构建镜像和单机容器编排docker-compose依然是最好的选择,所以我们还是要对docker有所了解才行。docker容器化面世很早,所以现在大家提到容器技术就想到docker,docker俨然成为了容器技术的代名词了,那我们该如何击败这个docker呢,下面我们仔细分析下docker它的各个属性和技能吧。
k8s1.24 中的移除和弃用官方文档:https://kubernetes.io/zh-cn/blog/2022/04/07/upcoming-changes-in-kubernetes-1-24/
Docker是dotCloud公司用Google公司推出的Go语言开发实现,基于Linux内核的namespace、cgroup,以及AUFS类的Union FS等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。
下面的图片比较了 Docker 和传统虚拟化方式的不同之处。传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
为什么要使用 Docker?
- 更高效的利用系统资源
- 更快速的启动时间
- 一致的运行环境
- 持续交付和部署
- 更轻松的迁移
- 更轻松的维护和扩展
对比传统虚拟机总结
特性 | 容器 | 虚拟机 |
---|---|---|
启动 | 秒级 | 分钟级 |
硬盘使用 | 一般为 MB | 一般为 GB |
性能 | 接近原生 | 弱于 |
系统支持量 | 单机支持上千个容器 | 一般几十个 |
docker的三板斧分别是:
- 镜像(
Image
) - 容器(
Container
) - 仓库(
Repository
)
docker的必杀技是:
- Dockerfile
下面以生产中实际的案例来让大家熟悉docker的整个生命周期,确保将其一击即溃。
python
FROM python:3.7-slim-stretch
MAINTAINER boge <Wx:bogeit>
WORKDIR /app
COPY requirements.txt .
RUN sed -i 's/deb.debian.org/ftp.cn.debian.org/g' /etc/apt/sources.list \
&& sed -i 's/security.debian.org/ftp.cn.debian.org/g' /etc/apt/sources.list \
&& apt-get update -y \
&& apt-get install -y wget gcc libsm6 libxext6 libglib2.0-0 libxrender1 git vim \
&& apt-get clean && apt-get autoremove -y && rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple -r requirements.txt \
&& rm requirements.txt
COPY . .
EXPOSE 5000
HEALTHCHECK CMD curl --fail http://localhost:5000 || exit 1
ENTRYPOINT ["gunicorn", "app:app", "-c", "gunicorn_config.py"]
golang
# stage 1: build src code to binary
FROM golang:1.13-alpine3.10 as builder
MAINTAINER boge <Wx:bogeit>
ENV GOPROXY https://goproxy.cn
ENV GO111MODULE on
COPY *.go /app/
RUN cd /app && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o hellogo .
# stage 2: use alpine as base image
FROM alpine:3.10
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
apk update && \
apk --no-cache add tzdata ca-certificates && \
cp -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
# apk del tzdata && \
rm -rf /var/cache/apk/*
COPY --from=builder /app/hellogo /hellogo
CMD ["/hellogo"]
nodejs
FROM node:12.6.0-alpine
MAINTAINER boge <Wx:bogeit>
WORKDIR /app
COPY package.json .
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
apk update && \
yarn config set registry https://registry.npm.taobao.org && \
yarn install
RUN yarn build
COPY . .
EXPOSE 6868
ENTRYPOINT ["yarn", "start"]
java
FROM maven:3.6.3-adoptopenjdk-8 as target
ENV MAVEN_HOME /usr/share/maven
ENV PATH $MAVEN_HOME/bin:$PATH
COPY settings.xml /usr/share/maven/conf/
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline # use docker cache
COPY src/ /build/src/
RUN mvn clean package -Dmaven.test.skip=true
FROM java:8
WORKDIR /app
RUN rm /etc/localtime && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY --from=target /build/target/*.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java","-Xmx768m","-Xms256m","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar"]
docker的整个生命周期展示
# 登陆docker镜像仓库
docker login "仓库地址" -u "仓库用户名" -p "仓库密码"
# 从仓库下载镜像
docker pull "仓库地址"/"仓库命名空间"/"镜像名称":latest || true
# 基于Dockerfile构建本地镜像
docker build --network host --build-arg PYPI_IP="xx.xx.xx.xx" --cache-from "仓库地址"/"仓库命名空间"/"镜像名称":latest --tag "仓库地址"/"仓库命名空间"/"镜像名称":"镜像版本号" --tag "仓库地址"/"仓库命名空间"/"镜像名称":latest .
# 将构建好的本地镜像推到远端镜像仓库里面
docker push "仓库地址"/"仓库命名空间"/"镜像名称":"镜像版本号"
docker push "仓库地址"/"仓库命名空间"/"镜像名称":latest
# 基于redis的镜像运行一个docker实例
docker run --name myredis --net host -d redis:6.0.2-alpine3.11 redis-server --requirepass boGe666
开始实战,迎击第4关的小BOOS战,获取属于我们的经验值
我们这里分别用python以及golang语言代码来打包镜像
python
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World! 23.10.20.01'
@app.route('/gg/<username>')
def hello(username):
return 'welcome' + ': ' + username + '!'
# gunicorn_config.py
bind = '0.0.0.0:5000'
graceful_timeout = 3600
timeout = 1200
max_requests = 1200
workers = 1
worker_class = 'gevent'
# requirements.txt
flask
gevent
gunicorn
# Dockerfile
FROM python:3.9.17-slim-bullseye
MAINTAINER WX:bogeit
WORKDIR /app
COPY requirements.txt .
RUN sed -i 's/deb.debian.org/ftp.cn.debian.org/g' /etc/apt/sources.list \
&& sed -i 's/security.debian.org/ftp.cn.debian.org/g' /etc/apt/sources.list \
&& apt-get update -y \
&& apt-get install -y wget gcc libsm6 libxext6 libglib2.0-0 libxrender1 make \
&& apt-get clean && apt-get autoremove -y && rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple -r requirements.txt \
&& rm requirements.txt
# 指定多个pip安装源
# pip install -r requirements.txt -i http://mirrors.aliyun.com/pypi/simple/ --extra-index-url https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host mirrors.aliyun.com --trusted-host pypi.tuna.tsinghua.edu.cn \
COPY . .
EXPOSE 5000
HEALTHCHECK CMD curl --fail http://localhost:5000 || exit 1
ENTRYPOINT ["gunicorn", "app:app", "-c", "gunicorn_config.py"]
golang
hellogo.go
// hellogo.go
package main
import (
"fmt"
"log"
"math/rand"
"net/http"
"time"
)
var appVersion = "23.10.20.01" //Default/fallback version
func NowTime(t time.Time) string {
nowtime := fmt.Sprintf("%4d-%02d-%02d %02d:%02d:%02d",
t.Year(), t.Month(), t.Day(),
t.Hour(), t.Minute(), t.Second())
return nowtime
}
func GetRandomString(l int) string {
str := "0123456789abcdefghijklmnopqrstuvwxyz"
bytes := []byte(str)
result := []byte{}
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return string(result)
}
func getFrontpage(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, Go! I'm instance %s running version %s at %s\n", GetRandomString(6), appVersion, NowTime(time.Now()))
}
func health(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
if http.StatusOK == 200{
fmt.Fprintf(w, "%s\n", "ok")
}
}
func getVersion(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s\n", appVersion)
}
func main() {
rand.Seed(time.Now().UTC().UnixNano())
http.HandleFunc("/", getFrontpage)
http.HandleFunc("/health", health)
http.HandleFunc("/version", getVersion)
log.Fatal(http.ListenAndServe(":3000", nil))
}
Dockerfile
# Dockerfile
# a demon for containerize golang web apps
#
# @author: boge
# @mail: Wx:bogeit
# stage 1: build src code to binary
FROM golang:1.19.11-alpine3.18 as builder
ENV GOPROXY https://goproxy.cn
COPY *.go /app/
RUN cd /app \
&& go mod init github.com/bogeit/golangtest \
&& go mod tidy \
&& CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o hellogo .
# stage 2: use alpine as base image
FROM alpine:3.18
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
apk update && \
apk --no-cache add tzdata ca-certificates && \
cp -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
# apk del tzdata && \
rm -rf /var/cache/apk/*
COPY --from=builder /app/hellogo /hellogo
CMD ["/hellogo"]
创建2个目录,一个python,一个golang,分别把上面对应的内容保存为文件
# 先打包python项目的镜像并运行测试
cd python
docker build -t python/flask:v0.0.1 .
docker run -d -p 80:5000 python/flask:v0.0.1
# 再打包golang项目的镜像并运行测试
cd golang
docker build -t boge/golang:v0.0.1 .
docker run -d -p80:3000 boge/golang:v0.0.1
更多推荐
所有评论(0)