images里到底有什么?操作系统、核心代码、系统工具、系统库、运行时的环境
为什么要制作镜像,github上不是有很多镜像吗?不能完全满足我们的要求;不够安全,会有安全隐患
制作镜像小的优点:
1.用户下载快
2.存储消耗的磁盘空间小
3.运行容器时消耗的内存小
制作小镜像的思想:
1.使用基础镜像小
2.少使用RUN、COPY、ADD、WORKDIR(这些指令会增加层数)
3.使用镜像启动容器后,再在里面安装软件,使用卷挂载数据
镜像分层
镜像分层的思想:一个镜像是由很多层数据组成
base镜像:提供的是最小安装的linux发行版
scratch镜像:一个空镜像,可以用于构建busybox等超小镜像,不依赖其他镜像
当容器启动时,一个新的可写层会被加载到镜像的顶部,这一层被称为“容器层”,“容器层”之下的都被称为“镜像层”,所有对容器的改动(添加、删除、修改)都只会发生到容器层中。容器启动的时候,内核启动bootfs(容器启动的时候需要的内容)后直接将基础镜像加载,然后一层一层自下而上的加载;容器运行后访问文件的时候,从上而下,一层一层的往下访问
镜像分层的好处:共享资源,容易实现资源复用
Dockerfile
Dockerfile是制作镜像的配置文件--配方文件
Dockerfile指令--一般写成大写:
指令 | 作用 | 备注 |
FROM | 指定基础镜像 | |
WORKDIR | 指定进入容器的时候在哪个目录下 | 该指令也会增加镜像层数--如果工作目录不是/目录(自定义目录)就会增加,是/就不会增加镜像的层数 |
ADD | 将宿主机里的文件或目录复制到容器里的某个目录下,与COPY指令作用一样 | |
RUN | 指定在制作镜像进行时运行的命令 | |
CMD | 启动容器时运行的程序,比较老的用法 | |
ENTRYPOINT | 启动容器时运行的程序,比较新的用法 | 与CMD指令同时存在时,以ENTRYPOINT指令为准,CMD里面的内容会成为ENTRYPOINT里的参数 |
ENV | 定义环境变量 | |
EXPOSE | 声明开放的端口号 | |
VOLUME | 在容器里使用卷,就是将容器里的某个路径挂载到宿主机的卷上 | 如:VOLUME /var/lib/mysql,就是在宿主机创建一个卷,名字会随机产生,会挂载到容器里的/var/lib/mysql |
STOPSIGNAL | 声明停止容器运行的信号 | |
HEALTHCHECK | 设置检查容器健康状况的命令 | 检测容器是否还在正常运行,能否对外提供服务 |
案例1:使用go语言编译好的代码制作镜像
提前安装go语言环境:
[root@sc-docker go]# yum install epel-release -y
[root@sc-docker go]# yum install golang -y
1.编写一个简单的web服务器的代码server.go
package main
//server.go是主运行文件
import (
"net/http"
"github.com/gin-gonic/gin"
)
//gin-->go中的web框架
//入口函数
func main(){
//创建一个web服务器
r:=gin.Default()
// 当访问/=>返回{"message":"hello, sanchuang"}
r.GET("/",func(c *gin.Context){
//200,返回的数据
c.JSON(http.StatusOK,gin.H{
"message":"hello,sanchuanger 2023 nice",
})
})
//运行web服务
r.Run()
}
编译server.go成一个二进制文件,放入镜像中的需要是一个二进制文件,go语言必须要编译成二进制文件才能运行
[root@sc-docker go]# go mod init web
[root@sc-docker go]# go env -w GOPROXY=https://goproxy.cn,direct #指定国内的源
[root@sc-docker go]# go mod tidy
[root@sc-docker go]# go run server.go #运行代码,默认监听的是8080,这个步骤只是测试我们的server.go能否正常运行
[root@sc-docker go]# go build -o hnweb . #hnweb就是我们编译好的核心代码
2.编写Dockerfile文件
[root@sc-docker go]# vim Dockerfile
[root@sc-docker go]# cat Dockerfile
FROM centos:7
WORKDIR /go
COPY . /go
RUN ls /go && pwd
ENTRYPOINT ["/go/hnweb"]
3.制作镜像
[root@sc-docker go]# docker build -t hnweb:1.0 .
[root@sc-docker go]# docker images #查看是否制作成功
REPOSITORY TAG IMAGE ID CREATED SIZE
hnweb 1.0 f9cc1be0bde6 About a minute ago 221MB
...
其中docker build命令中:-t选项用于指定镜像的名字,最后那个.表示是根据当前文件夹里的Dockerfile文件进行制作
4.启动容器使用镜像hnweb
[root@sc-docker go]# docker run -d --name hnweb-1 -p 7788:8080 hnweb:1.0
83dd8736d8dcaa846e705bef729b21440925cd94b4fa105a6f5e64fc369ad775
5.去浏览器或其他机器访问宿主机ip+端口号,查看是否使用成功
案例二:以nginx为基础镜像编写Dockerfile,并构建一个名为nginxtest的镜像,要求镜像内安装一个tcpdump工具,下载或从本地拉取一个tar包并解压,构建镜像后运行容器,并暴露端口访问。
[root@sc-docker yuan]# cat Dockerfile
FROM nginx:latest
WORKDIR /
RUN apt-get update && apt-get install tcpdump -y
RUN curl -O https://nginx.org/download/nginx-1.25.1.tar.gz && tar xf nginx-1.25.1.tar.gz
ENTRYPOINT ["/docker-entrypoint.sh"] #核心程序使用基础镜像中的,最后4行都是基于nginx镜像中的
EXPOSE 80
STOPSIGNAL SIGQUIT
CMD ["nginx", "-g", "daemon off;"]
[root@sc-docker yuan]# docker build -t sumengnginx:1.0 .
[root@sc-docker yuan]# docker run -d -p 4433:80 --name su-nginx-1 sumengnginx:1.0
8521143e2255c49e268e07165ee253e0b91a955f1eb86931dedb011de03a825a
补充:nginx使用的是Debian系统
root@83c27adccd24:/# cat /etc/issue
Debian GNU/Linux 11 \n \l
在Debian系统中安装tcpdump命令:
root@018ecad85391:/# apt-get update #更新Debian系统的仓库的源文件-->告诉系统去哪里可以下载软件,等同于centos中下载.repo文件
root@018ecad85391:/# apt-get install tcpdump -y