docker镜像操作实操

C++Hello world镜像制作

  • 创建目录,在目录下创建c++源代码demo.c
bash 复制代码
mkdir 目录
cd 目录
vim demo.c
  • 创建Dockerfile
bash 复制代码
#指定基础镜像
FROM centos:7
#设置版本
ENV VWESION=1.0
#替换国内源
RUN sed -i 's|^mirrorlist=|#mirrorlist=|g' /etc/yum.repos.d/CentOS-Base.repo && \
    sed -i 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.aliyun.com/centos-vault/centos|g' /etc/yum.repos.d/CentOS-Base.repo && \
    yum clean all && yum makecache
#设置工作目录
WORKDIR /src
#拷贝源文件
COPY demo.c .
#安装gcc
RUN yum makecache && yum install gcc -y
#编译源文件
RUN gcc demo.c -o demo && \
	rm -f demo.c && \
	yum remove -y gcc
#运行可执行文件
CMD ["/src/demo"] 
  • 执行构建,运行镜像查看结果
bash 复制代码
docker build -t cpp:v0.1 .
docker run --name test1 --rm cpp:v0.1

CMD和ENTRYPOINT

这两个指令都是在docker image中执行一条命令,但它们之间有区别。

执行一个没有调用ENTRYPOINT或者CMD的docker镜像会返回错误,一般的镜像最后都提供了CMD或者ENTRYPOINT作为入口。

操作

覆盖

在写dockerfile时,ENTRYPOINT或者CMD命令会自动覆盖之前的ENTRYPOINT或者CMD命令,用户也可以在命令中指定具体命令,如果不希望docker镜像执行的具体程序被用户执行docker run覆盖,可以使用ENTRYPOINT。
多次覆盖

  • 创建一个Dockerfile,指定多个CMD
bash 复制代码
FROM busybox
CMD echo "hello world"
CMD echo "hello vientiane"
  • 编译运行,可以看到第一个CMD被覆盖了

    参数覆盖
  • 在docker run的时候指定后面的启动参数
bash 复制代码
FROM busybox
CMD echo "hello world"
CMD echo "hello vientiane"
bash 复制代码
docker run --name test1 --rm cpp:v0.2 echo "hello CMD"
  • 但如果是ENTRYPOINT的话,那无法覆盖,除非指定参数--entrypoint

Shell和Exec

  • 编写Dockerfile,执行ping命令
bash 复制代码
FROM ubuntu:22.04
RUN apt-get update -y && apt install -y iputils-ping
CMD ping localhost
  • 编译镜像,进入镜像里面查看,可以看到pid为1的是/bin/sh

  • 但如果使用exec模式,可以看到pid为1的进程是ping而不是/bin/sh

组合

  • 新建dockerfile,同时设置ENTRYPOINT和CMD
bash 复制代码
FROM ubuntu:22.04
RUN apt-get update -y && apt install -y iputils-ping
ENTRYPOINT ["/bin/ping","-c","3"]
CMD ["localhost"] 
  • 编译镜像后启动运行,可以看到CMD的内容作为ENTRYPOINT的参数添加到了后面
bash 复制代码
docker build -t cpp:v0.4 .
docker run --name test1 --rm cpp:v0.4
  • 因为CMD的内容可以更换,如果我们运行的时候替换成另外一个网址,我们就可以看到它ping的是另外一个网址
bash 复制代码
docker run --name test1 --rm cpp:v0.4 www.baidu.com

dockerignore

docker是C-S架构,理论上Client和Server可以不在一台机器上,在构建docker镜像的时候,需要把文件从Client发送给Server,这些要发送的文件成为欸build context。

bash 复制代码
docker build -f <dockerfile> -t <dockerfilename> .

如果想要忽略掉一些传输给server短的文件,就会用到.dockerignore文件,它会将有记录的所有文件都忽略掉,不会传输给server端。

操作

  • 建立dockerfile
bash 复制代码
FROM centos:7
COPY ./* /
  • 建立.dockerignore文件,忽略以txt为后缀的文件,在文件里输入*.txt
bash 复制代码
cat .dockerignore
  • 制造一些文件
bash 复制代码
touch 1.txt 2.txt 3.doc 4.rtf
  • 构建镜像并查看结果
bash 复制代码
docker build -f ./dockerfile -t cpp:v0.6 .
docker run -it cpp:v0.6

多阶段构建

构建docker镜像有两种方式,第一种是将全部组件及其依赖库的编译,测试,打包流程都封装仅一个docker镜像中,第二种是将每个阶段分散到多个dockerfile。
单文件构建

  • 创建目录,在目录下创建c++源代码demo.c
bash 复制代码
mkdir 目录
cd 目录
vim demo.c
  • 创建Dockerfile
bash 复制代码
#指定基础镜像
FROM centos:7
#设置版本
ENV VWESION=1.0
#替换国内源
RUN sed -i 's|^mirrorlist=|#mirrorlist=|g' /etc/yum.repos.d/CentOS-Base.repo && \
    sed -i 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.aliyun.com/centos-vault/centos|g' /etc/yum.repos.d/CentOS-Base.repo && \
    yum clean all && yum makecache
#设置工作目录
WORKDIR /src
#拷贝源文件
COPY demo.c .
#安装gcc
RUN yum makecache && yum install gcc -y
#编译源文件
RUN gcc demo.c -o demo && \
	rm -f demo.c && \
	yum remove -y gcc
#运行可执行文件
CMD ["/src/demo"] 
  • 执行构建,运行镜像查看结果,可以看到生成的镜像很大
bash 复制代码
docker build -t cpp:v0.1 .
docker run --name test1 --rm cpp:v0.8
docker image ls | grep cpp


多阶段构建

实际上我们把test.c编译完之后,并不需要一个大的gcc编译环境,只需要一个小的运行环境镜像即可。

  • 创建目录,在目录下创建c++源代码demo.c
bash 复制代码
mkdir 目录
cd 目录
vim demo.c
  • 创建Dockerfile
bash 复制代码
#第一阶段构建
#指定基础镜像
FROM centos:7 as base
#设置版本
ENV VWESION=1.0
#替换国内源
RUN sed -i 's|^mirrorlist=|#mirrorlist=|g' /etc/yum.repos.d/CentOS-Base.repo && \
    sed -i 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.aliyun.com/centos-vault/centos|g' /etc/yum.repos.d/CentOS-Base.repo && \
    yum clean all && yum makecache
#设置工作目录
WORKDIR /src
#拷贝源文件
COPY demo.c .
#安装gcc
RUN yum makecache && yum install gcc -y
#编译源文件
RUN gcc demo.c -o demo && \
	rm -f demo.c && \
	yum remove -y gcc
#运行可执行文件
CMD ["/src/demo"] 

#第二阶段构建
FROM centos:7
#拷贝第一阶段生成的可执行程序
COPY --from=base /src/demo /src/demo
#运行可执行程序
CMD ["/src/demo"]
  • 执行构建,运行镜像查看结果,可以看到生成的镜像变小了很多
bash 复制代码
docker build -t cpp:v0.9 .
docker run --name test1 --rm cpp:v0.9
docker image ls | grep cpp
  • 当我们使用busybox这一类更小的镜像的时候,会发现构建完之后的镜像更小了
  • 创建Dockerfile
bash 复制代码
#第一阶段构建
#指定基础镜像
FROM centos:7 as base
#设置版本
ENV VWESION=1.0
#替换国内源
RUN sed -i 's|^mirrorlist=|#mirrorlist=|g' /etc/yum.repos.d/CentOS-Base.repo && \
    sed -i 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.aliyun.com/centos-vault/centos|g' /etc/yum.repos.d/CentOS-Base.repo && \
    yum clean all && yum makecache
#设置工作目录
WORKDIR /src
#拷贝源文件
COPY demo.c .
#安装gcc
RUN yum makecache && yum install gcc -y
#编译源文件
RUN gcc demo.c -o demo && \
	rm -f demo.c && \
	yum remove -y gcc
#运行可执行文件
CMD ["/src/demo"] 

#第二阶段构建
FROM busybox
#拷贝第一阶段生成的可执行程序
COPY --from=base /src/demo /src/demo
#运行可执行程序
CMD ["/src/demo"]
  • 执行构建,运行镜像查看结果,可以看到生成的镜像只有几MB
bash 复制代码
docker build -t cpp:v0.1 .
docker run --name test1 --rm cpp:v1.0
docker image ls | grep cpp

使用缓存

在镜像构建过程中,docker会根据dockerfile指定的顺序执行每一个指令,在执行每一条指令之前,docker都会在缓存中查找是否存在可重用的镜像,如果有就使用现存的镜像,不会重复创建。

如果在构建的时候不想使用缓存,可以在docker build中使用--no-cache=true。

操作

  • 改变源代码文件demo.c重新构建镜像,这里也并没有使用到缓存,所以也需要构建很久。要怎么避免这种情况呢?
bash 复制代码
#第一阶段构建
#指定基础镜像
FROM centos:7 as base
#设置版本
ENV VWESION=1.0
#替换国内源
RUN sed -i 's|^mirrorlist=|#mirrorlist=|g' /etc/yum.repos.d/CentOS-Base.repo && \
    sed -i 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.aliyun.com/centos-vault/centos|g' /etc/yum.repos.d/CentOS-Base.repo && \
    yum clean all && yum makecache
#设置工作目录
WORKDIR /src
#拷贝源文件
COPY demo.c .
#安装gcc
RUN yum makecache && yum install gcc -y
#编译源文件
RUN gcc demo.c -o demo && \
	rm -f demo.c && \
	yum remove -y gcc
#运行可执行文件
CMD ["/src/demo"] 

#第二阶段构建
FROM busybox
#拷贝第一阶段生成的可执行程序
COPY --from=base /src/demo /src/demo
#运行可执行程序
CMD ["/src/demo"]
  • 可以将不经常修改的内容调节到dockerfile前边,经常修改的内容放在dockerfile文件后面(这里将COPY往后挪了),这样就可以尽量多的复用缓存了。
bash 复制代码
#第一阶段构建
#指定基础镜像
FROM centos:7 as base
#设置版本
ENV VWESION=1.0
#替换国内源
RUN sed -i 's|^mirrorlist=|#mirrorlist=|g' /etc/yum.repos.d/CentOS-Base.repo && \
    sed -i 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.aliyun.com/centos-vault/centos|g' /etc/yum.repos.d/CentOS-Base.repo && \
    yum clean all && yum makecache
#设置工作目录
WORKDIR /src
#安装gcc
RUN yum makecache && yum install gcc -y
#拷贝源文件
COPY demo.c .
#编译源文件
RUN gcc demo.c -o demo && \
	rm -f demo.c && \
	yum remove -y gcc
#运行可执行文件
CMD ["/src/demo"] 

#第二阶段构建
FROM busybox
#拷贝第一阶段生成的可执行程序
COPY --from=base /src/demo /src/demo
#运行可执行程序
CMD ["/src/demo"]

这里仅用了1.7s

搭建MySQL主从同步

在docker-compose.yml文件中可以使用build选项来编译镜像。

bash 复制代码
service:
#格式1,指定的上下文目录是./web,在构建的时候会自动在此目录下寻找Dockerfile,构建完后,镜像命名为test/web
	frontend:
		image: test/web
		build: ./web
#格式2,指定的上下文目录是./database,在构建的时候会自动在此目录下寻找backend.dockerfile,构建完后,镜像命名为test/database
	backend:
		image:test/database
		build:
			context: ./database
			dockerfile: ./backend.dockerfile

编辑完后,就使用docker compose build来构建所有服务的镜像。

操作

创建一个一主二从的MySQL集群

  • 创建目录
bash 复制代码
mkdir -p ./mysqlcluster
mkdir -p ./mysqlcluster/master
mkdir -p ./mysqlcluster/slave
  • 进入./mysqlcluster/master,创建主dockerfile文件名为Dockerfile-master,配置系统时区为上海
bash 复制代码
FROM mysql:5.7.36
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
  • 进入./mysqlcluster/slave,创建从dockerfile,文件名为Dockerfile-slave,配置系统时区为上海
bash 复制代码
FROM mysql:5.7.36
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY ./slave/slave.sql /docker-entrypoint-initdb.d
  • 创建从库配置脚本slave.sql
bash 复制代码
change master to master_host='mysql-master'
master_user='root',master_password='root',master_port=3306;
start slave;
  • 进入./mysqlcluster目录,创建docker-compose.yml配置文件
bash 复制代码
version: "3"

services:
  # MySQL 主节点
  mysql-master:
    build:
      context: ./
      dockerfile: ./master/Dockerfile-master
    image: mysqlmaster:v1.0
    restart: always
    container_name: mysql-master
    volumes:
      - ./mastervarlib:/var/lib/mysql
    ports:
      - 9306:3306
    environment:
      MYSQL_ROOT_PASSWORD: root
    privileged: true
    command: 
      - '--server-id=1'
      - '--log-bin=master-bin'
      - '--binlog-ignore-db=mysql'
      - '--binlog_cache_size=256M'
      - '--binlog_format=mixed'
      - '--lower_case_table_names=1'
      - '--character-set-server=utf8'
      - '--collation-server=utf8_general_ci'

  # MySQL 从节点1
  mysql-slave:
    build:
      context: ./
      dockerfile: ./slave/Dockerfile-slave
    image: mysqlslave:v1.0
    restart: always
    container_name: mysql-slave
    volumes:
      - ./slavevarlib:/var/lib/mysql
    ports:
      - 9307:3306
    environment:
      MYSQL_ROOT_PASSWORD: root
    privileged: true
    command: 
      - '--server-id=2'
      - '--relay_log=slave-relay'
      - '--lower_case_table_names=1'
      - '--character-set-server=utf8'
      - '--collation-server=utf8_general_ci'
    depends_on:
      - mysql-master

  # MySQL 从节点2
  mysql-slave2:
    build:
      context: ./
      dockerfile: ./slave/Dockerfile-slave
    image: mysqlslave:v1.0
    restart: always
    container_name: mysql-slave2
    volumes:
      - ./slavevarlib2:/var/lib/mysql
    ports:
      - 9308:3306
    environment:
      MYSQL_ROOT_PASSWORD: root
    privileged: true
    command: 
      - '--server-id=3'
      - '--relay_log=slave-relay'
      - '--lower_case_table_names=1'
      - '--character-set-server=utf8'
      - '--collation-server=utf8_general_ci'
    depends_on:
      - mysql-master
  • 构建镜像
bash 复制代码
docker compose build
  • 启动服务进行测试
bash 复制代码
docker compose up
  • 查看状态
bash 复制代码
docker compose ps
  • 连接主库,查看数据库可以看到运行正常
bash 复制代码
docker exec -it mysql-master bash
  • 查看数据库角色和同步状态
bash 复制代码
show master status\G
  • 在主库上创建数据库,连接上任意一个从库,查从库数据库
相关推荐
徐子元竟然被占了!!2 小时前
DNS-特殊域名
运维
CDN3602 小时前
CDN 缓存不生效 / 内容不更新?7 种原因 + 一键刷新方案
运维·网络安全·缓存
野木香2 小时前
fnm在win10下安装配置
运维·学习
F1FJJ3 小时前
VS Code 里管理 PostgreSQL,有哪些选择?主流扩展横向对比
网络·数据库·postgresql·容器
wydaicls3 小时前
什么时候触发负载均衡(kernel 6.12)
运维·负载均衡
kainx3 小时前
Linux编译eeprom
linux·运维·c语言·eeprom
攻城狮在此3 小时前
MobaXterm下载安装及SSH远程连接(交换机/路由器/服务器)
linux·运维·服务器·网络
花间相见3 小时前
【Agent开发】—— ToolCall 、 FunctionCall 底层原理与极简实现
运维·服务器
说实话起个名字真难啊3 小时前
docker入门之单进程哲学与多进程管理
docker