Linux进阶 | 万字详解Docker镜像的制作,手把手学会!

Posted chaochao️

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux进阶 | 万字详解Docker镜像的制作,手把手学会!相关的知识,希望对你有一定的参考价值。

  创作不易,来了的客官点点关注,收藏,订阅一键三连❤😜  


前言

运维之基础——Linux。我是一个即将毕业的大学生,超超。如果你也在学习Linux,不妨跟着萌新超超一起学习Linux,拿下Linux,一起加油,共同努力,拿到理想offer!


系列文章

Linux进阶 | Docker部署nginx的web服务,VOLUME的使用详解,实现数据持久化!

Linux进阶 | 2万字总结最详细的Docker的安装、底层隔离机制和简单使用!建议收藏,持续更新❤

Linux | 详解系统监控和常用命令(top free dstat)

Linux 超超讲解SSH的原理与SSH的实现!建议收藏❤


概述

Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。本期内容为Docker第三期,通过本期内容将会掌握docker的镜像制作。


目录

前言

概述

超超Docker学习思维导图 

镜像的概念

Base镜像

Bootfs与rootfs

镜像的分层结构

镜像的制作

制作前的疑问

Dockerfile

制作步骤

以制作nginx镜像为例启动web服务

自己练习制作nginx镜像

练习

练习一:以python:3.9镜像为基础创建镜像,并以此启动容器并连接到redis

练习二:实现docker官网的镜像制作


超超Docker学习思维导图 

Docker思维导图将持续更新,欢迎大家订阅Linux栏目! 


镜像的概念

Base镜像

Base 镜像有两层含义

1. 不依赖其他镜像,从 scratch 构建。
2. 其他镜像可以之为基础进行扩展。

Base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等,以 CentOS 为例学习 base 镜像包含哪些内容。

[root@docker ~]# docker images centos

REPOSITORY   TAG       IMAGE ID       CREATED        SIZE

centos       7         8652b9f0cb4c   9 months ago   204MB

使用docker pull centos下载最新版本的Centos镜像也就207M左右,而我们平时下载一个原生的centos镜像都是4G。

容器只能使用 Host kernel,并且不能修改。所有容器都共用 host kernel,在容器中没办法对 kernel 升级。如果容器对 kernel 版本有要求(比如应用只能在某个 kernel 版本下运行),则不建议用容器,这种场景虚拟机可能更合适。

Bootfs与rootfs

Bootfs:内核空间是 kernel,Linux 刚启动时会加载 bootfs 文件系统,之后 bootfs 会被卸载掉。

rootfs:容器内部的操作系统,用户空间的文件系统是 rootfs,包含我们熟悉的 /dev, /proc, /bin 等目录。

镜像的分层结构

Docker 支持通过扩展现有镜像,创建新的镜像。实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。


镜像的制作

制作前的疑问

镜像是什么?

答案:镜像由程序代码、基础操作系统、基础软件组成。

      镜像是一个文件,里面包含了程序代码、基础操作系统、基础软件。

为什么要制作镜像,docker hub上不是有很多镜像吗?

答案:

    1.不能满足我们的需要

    2.不够安全,有安全隐患

谁去制作镜像?

答案: 一般都是开发人员去制作

        也可以是运维人员去制作、权利非常大的工作人员。

镜像里有什么?

1.base 镜像 --》基础镜像--》提供操作系统,其他软件最基本的功能

基础镜像里的操作系统:Ubuntu、debian、centos等

Dockerfile

如果你想要从一个基础镜像开始建立一个自定义镜像,可以选择一步一步进行构建,也可以选择写一个配置文件,然后一条命令(docker build)完成构建,显然配置文件的方式可以更好地应对需求的变更,这个配置文件就是Dockerfile。

那DockerFile是什么?

Dockerfile: 用于描述镜像的生成规则(配置文件),Dockerfile中的每一条命令,都在Docker镜像中以一个独立镜像层的形式存在

DockerFile就类似与Linux的shell脚本,只不过DockerFile是用来构建镜像的

制作步骤

以制作nginx镜像为例启动web服务

1.新建一个空目录

[root@docker ~]# cd /mydocker/

[root@docker mydocker]# pwd

/mydocker

2.新建Dockerfile

[root@docker mydocker]# vim Dockerfile

[root@docker mydocker]# ls

Dockerfile

[root@docker mydocker]# cat Dockerfile

# Use an official Python runtime as a parent image  下载一个python2.7的镜像模板,已经有操作系统和安装好python2.7

FROM python:2.7-slim

 

# Set the working directory to /app   #在docker容器里的工作目录-->进入docker容器的时候,所在的目录

WORKDIR /app

 

# Copy the current directory contents into the container at /app  复制当前目录下的所有的内容到容器里的/app目录下

ADD . /app

 

VOLUME ["/data_flask"]

 

# Install any needed packages specified in requirements.txt 制作镜像的时候运行

RUN pip install --trusted-host pypi.python.org -r requirements.txt

 

# Make port 80 available to the world outside this container

EXPOSE 80

 

# Define environment variable 设置环境变量,app.py运行时可以调用

ENV NAME World

 

# Run app.py when the container launches 容器启动时运行

CMD ["python", "app.py"]

3.新建requirements.txt文件

[root@docker mydocker]# vim requirements.txt

[root@docker mydocker]# ls

Dockerfile  requirements.txt

[root@docker mydocker]# cat requirements.txt

Flask

Redis

4.新建app.py文件

[root@docker mydocker]# vim app.py

[root@docker mydocker]# ls

app.py  Dockerfile  requirements.txt

[root@docker mydocker]# cat app.py

from flask import Flask

from redis import Redis, RedisError

import os

import socket

 

# Connect to Redis

redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)

 

app = Flask(__name__)

 

@app.route("/")

def hello():

    try:

        visits = redis.incr("counter")

    except RedisError:

        visits = "<i>cannot connect to Redis, counter disabled</i>"

 

    html = "<h3>Hello {name}!</h3>" \\

           "<b>Hostname:</b> {hostname}<br/>" \\

           "<b>Visits:</b> {visits}"

    return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)

 

if __name__ == "__main__":

    app.run(host='0.0.0.0', port=80)

[root@docker mydocker]#

5.生成镜像,需要一点时间,因为下载安装很多东西

[root@docker mydocker]# docker build -t hellochao .

-t 指定要创建的目标镜像名

. Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径

注:此时可能会有错误爆出,是由于网络连接问题所导致。

解决方法:重启docker服务。

6.查看生成的镜像

[root@docker mydocker]# docker images

REPOSITORY                 TAG        IMAGE ID       CREATED          SIZE

hellochao                  latest     b9cdb67a8db4   14 seconds ago   159MB

<none>                     <none>     fbea61ffb278   32 minutes ago   148MB

ubuntu-chaochao            2.0        67596afe27b5   4 days ago       72.8MB

ubuntu                     latest     1318b700e415   3 weeks ago      72.8MB

redis                      latest     aa4d65e670d6   3 weeks ago      105MB

nginx                      latest     08b152afcfae   3 weeks ago      133MB

mysql                      5.7.35     8cf625070931   3 weeks ago      448MB

daocloud.io/nginx          latest     6084105296a9   5 months ago     133MB

hello-world                latest     d1165f221234   5 months ago     13.3kB

centos                     7          8652b9f0cb4c   9 months ago     204MB

python                     2.7-slim   eeb27ee6b893   16 months ago    148MB

centos/python-35-centos7   latest     2db34dda8fd8   2 years ago      645MB

7.以刚刚创建的镜像为基础创建容器

[root@docker mydocker]# docker run -d --name hello-chao-1 -p 8013:80 hellochao

b571dc07bf393737fe820cf5a7b6c5c61359b9979054d3484aeb1d573a788d71

[root@docker mydocker]# docker ps

CONTAINER ID   IMAGE       COMMAND           CREATED         STATUS         PORTS                                   NAMES

b571dc07bf39   hellochao   "python app.py"   2 minutes ago   Up 2 minutes   0.0.0.0:8013->80/tcp, :::8013->80/tcp   hello-chao-1

访问方式1:

用浏览器访问:网站-->宿主机IP+端口号

访问方式2:curl IP地址:端口号

Hello World!

Hostname: f4aeb5d5305a

 Visits: cannot connect to Redis, counter disabled

因为redis数据库容器没有启动,flask web服务不能连接到redis数据库

8.启动redis容器

[root@docker mydocker]# docker run -d -p 6379:6379 --name hello-redis-1 redis

4ae649e2c9cf52e19e5cab4e4a6136d493390ff2e089838a4d65221e8e5b534a

9.再次启动一个自己制作镜像的容器,连接到redis容器

[root@docker mydocker]# docker run -d --name hello-chao-2 -p 8014:80 --link hello-redis-1:redis hellochao
1967d1eae722bd34e01f5bc575127e041a6caea15f48bd5f3f137ae1f2c744a9

10.访问web服务,效果如下:

方式一:用浏览器

 方式二:curl

[root@docker ~]# curl 192.168.232.132:8014

<h3>Hello World!</h3><b>Hostname:</b> 1967d1eae722<br/><b>Visits:</b> 3[root@docker ~]#

Dockerfile里面的RUNCMD是什么时候运行的?

RUN构建镜像时候运行的,在临时启动的中间测试的容器里运行,会产生中间的镜像层

CMD镜像制作好后,容器启动的时候运行

ADDCOPY

Dockerfile中的COPY指令和ADD指令都可以将主机上的资源复制或加入到容器镜像中,都是在构建镜像的过程中完成的

COPY指令和ADD指令的唯一区别在于是否支持从远程URL获取资源

COPY指令只能从执行docker build所在的主机上读取资源并复制到镜像中。

而ADD指令还支持通过URL从远程服务器读取资源并复制到镜像中。(推荐)


自己练习制作nginx镜像

1.部署环境

[root@docker ~]# mkdir/mydocker/nginx

2.创建Dockerfile

[root@docker nginx]# ls

Dockerfile  install_nginx.sh  nginx-1.21.1.tar.gz

[root@docker nginx]# vim Dockerfile

[root@docker nginx]# cat Dockerfile

FROM centos:7

ENV NGINX_VERSION 1.21.1

ENV AUTHOR ChaoChao

LABEL maintainer="lzc<2569138892@qq.com>"

RUN mkdir /nginx

WORKDIR /nginx

COPY . /nginx

RUN set -ex;\\

    bash install_nginx.sh ; \\

    yum install vim iputils net-tools iproute -y

EXPOSE 80

ENV PATH=/usr/local/nginx1/sbin:$PATH

 

STOPSIGNAL SIGQUIT

CMD ["nginx","-g","daemon off;"]

 

[root@docker nginx]#

3.构建nginx镜像

[root@docker nginx]#docker build -t chao-ngixn-1 .

[root@docker nginx]# docker images

REPOSITORY                 TAG         IMAGE ID       CREATED         SIZE

chao-nginx-1               latest      f668613a9de5   6 seconds ago   543MB

getting-started-1          latest      78bc6143bbce   7 hours ago     383MB

getting-started            latest      8224b1c2dc86   19 hours ago    374MB

hello-chao-3               latest      a9c7a3290464   20 hours ago    923MB

hellochao                  latest      b9cdb67a8db4   24 hours ago    159MB

<none>                     <none>      fbea61ffb278   24 hours ago    148MB

python                     3.9         4c7220cee541   31 hours ago    912MB

node                       12-alpine   dc1848067319   5 days ago      88.9MB

ubuntu-chaochao            2.0         67596afe27b5   5 days ago      72.8MB

ubuntu                     latest      1318b700e415   3 weeks ago     72.8MB

redis                      latest      aa4d65e670d6   3 weeks ago     105MB

nginx                      latest      08b152afcfae   3 weeks ago     133MB

mysql                      5.7.35      8cf625070931   3 weeks ago     448MB

daocloud.io/nginx          latest      6084105296a9   5 months ago    133MB

hello-world                latest      d1165f221234   5 months ago    13.3kB

centos                     7           8652b9f0cb4c   9 months ago    204MB

python                     2.7-slim    eeb27ee6b893   16 months ago   148MB

centos/python-35-centos7   latest      2db34dda8fd8   2 years ago     645MB

4.创建以新建镜像为基础的容器并测试是否实现功能

[root@docker nginx]# docker run -d --name chaochao-nginx-1 -p 8018:80 chao-nginx-1

fad41f8b6ee1da4034c8fd89a1a56c3588a28100850e7c5a9cfdb8f089eeef4f

[root@docker nginx]# curl 192.168.232.132:8018

<!DOCTYPE html>

<html>

<head>

<title>Welcome to nginx!</title>

<style>

    body {

        width: 35em;

        margin: 0 auto;

        font-family: Tahoma, Verdana, Arial, sans-serif;

    }

</style>

</head>

<body>

<h1>Welcome to nginx!</h1>

<p>If you see this page, the nginx web server is successfully installed and

working. Further configuration is required.</p>

 

<p>For online documentation and support please refer to

<a href="http://nginx.org/">nginx.org</a>.<br/>

Commercial support is available at

<a href="http://nginx.com/">nginx.com</a>.</p>

 

<p><em>Thank you for using nginx.</em></p>

</body>

</html>

[root@docker nginx]# docker exec -it chaochao-nginx-1 /bin/bash

[root@fad41f8b6ee1 nginx]# ls

Dockerfile  install_nginx.sh  nginx-1.21.1  nginx-1.21.1.tar.gz

[root@fad41f8b6ee1 nginx]# vim chaochao.txt

[root@fad41f8b6ee1 nginx]# cat chaochao.txt

echo I am chaochao!

[root@fad41f8b6ee1 nginx]# ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000

    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

    inet 127.0.0.1/8 scope host lo

       valid_lft forever preferred_lft forever

135: eth0@if136: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default

    link/ether 02:42:ac:11:00:0a brd ff:ff:ff:ff:ff:ff link-netnsid 0

    inet 172.17.0.10/16 brd 172.17.255.255 scope global eth0

       valid_lft forever preferred_lft forever

[root@fad41f8b6ee1 nginx]# exit

exit

[root@docker nginx]# ls

Dockerfile  install_nginx.sh  nginx-1.21.1.tar.gz

5.更改index.html

方法一:利用挂载实现

[root@docker nginx]# docker run -dp 8019:80 -v /web:/usr/local/nginx1/html --name chaochao-nginx-2 chao-nginx-1

6e3f9a849ce179ad184e2c314651c86a4db8c3c7ab5f264f0af27baa6aa1a047

[root@docker nginx]#

方法二:使用卷

[root@docker nginx]# docker volume create chao-nginx-volume-1

chao-nginx-volume-1

[root@docker nginx]# docker volume inspect chao-nginx-volume-1

[

    {

        "CreatedAt": "2021-08-18T17:20:27+08:00",

        "Driver": "local",

        "Labels": {},

        "Mountpoint": "/var/lib/docker/volumes/chao-nginx-volume-1/_data",

        "Name": "chao-nginx-volume-1",

        "Options": {},

        "Scope": "local"

    }

]

[root@docker nginx]# cd /var/lib/docker/volumes/chao-nginx-volume-1/_data

[root@docker _data]# cp /web/* .

[root@docker _data]# ls

1.jpg  index.html  rep.html

[root@docker _data]# docker run -dp 8020:80 --name chao-nginx-3 --mount source=chao-nginx-volume-1,target=/usr/local/nginx1/html/ chao-nginx-1

e0f8f8b0bfc40b8ad6d2e74a536b6e831dde444fbb8c536b37ead81e31c5d64c

练习

练习一:以python:3.9镜像为基础创建镜像,并以此启动容器并连接到redis

1.升级 hello-chao-1的镜像里的基础镜像为python:3.9,并将自己的镜像更名

2.启动容器和redis容器,测试访问

[root@docker ~]# cd mydocker2/

[root@docker mydocker2]# ls

[root@docker mydocker2]# cp /mydocker/* .

[root@docker mydocker2]# ls

app.py  Dockerfile  requirements.txt

[root@docker mydocker2]# vim Dockerfile

[root@docker mydocker2]# docker pull python:3.9

[root@docker mydocker2]# docker build -t hello-chao-3 .

[root@docker mydocker2]# curl 192.168.232.132:8015

<h3>Hello,I am Lizhichao!</h3><b>Hostname:</b> 232af106a331<br/><b>Visits:</b> <i>cannot connect to Redis, counter disabled</i>[root@docker mydocker2]#

[root@docker mydocker2]# docker run -d --name hello-redis-2 -p 8011:6379 redis

181d9b51863a6ad888e7e53ac27070343396fab16c911851dfa2c4e7579b7f22

[root@docker mydocker2]# docker run -d --name hello-chao-5 -p 8016:80 --link hello-redis-2:redis hello-chao-3

080bdc9dcd9304597c27db1afd6e266fd6d8c37ae78fcf02bedf81809a085470

[root@docker mydocker2]# curl 192.168.232.132:8016

<h3>Hello,I am Lizhichao!</h3><b>Hostname:</b> 080bdc9dcd93<br/><b>Visits:</b> 1[root@docker mydocker2]# curl 192.168.232.132:8016

<h3>Hello,I am Lizhichao!</h3><b>Hostname:</b> 080bdc9dcd93<br/><b>Visits:</b> 2[root@docker mydocker2]#

练习二:实现docker官网的镜像制作

实现 https://docs.docker.com/get-started/02_our_app/ 官网的镜像制作

[root@docker ~]# ls

anaconda-ks.cfg  getting-started-master.zip  mydocker2  ubuntu-chao2.tar  ubuntu-chao.tar

[root@docker ~]# unzip getting-started-master.zip

[root@docker ~]# ls

anaconda-ks.cfg  getting-started-master  getting-started-master.zip  mydocker2  ubuntu-chao2.tar  ubuntu-chao.tar

[root@docker ~]# cd getting-started-master

[root@docker getting-started-master]# ls

app       docker-compose.yml  docs         LICENSE     README.md         yarn.lock

build.sh  Dockerfile          Jenkinsfile  mkdocs.yml  requirements.txt

[root@docker getting-started-master]# cd app

[root@docker app]#

[root@docker app]# ls

package.json  spec  src  yarn.lock

[root@docker app]# vim Dockerfile

[root@docker app]# ls

Dockerfile  package.json  spec  src  yarn.lock

[root@docker app]# cat Dockerfile

#syntax=docker/dockerfile:1

FROM node:12-alpine

RUN apk add --no-cache python g++ make

WORKDIR /app

COPY . .

RUN yarn install --production

CMD ["node", "src/index.js"]

[root@docker app]#

[root@docker app]# docker run -dp 3000:3000 getting-started-1

588fd20a79b9d8082507dc209e73fa8a51a1e6abb56bc019256afc0df43ac73a

[root@docker app]#

[root@docker app]# docker run -dp 3001:3000 --name chao-node-2 getting-started-1

b5c8d74e7be4426fb22e1c524e26bead8b160cd938ae6bebe2433a52c65ab33a

[root@docker app]#

创作不易,客官点个赞,评论一下吧!超超和你一起加油❤😜

以上是关于Linux进阶 | 万字详解Docker镜像的制作,手把手学会!的主要内容,如果未能解决你的问题,请参考以下文章

详解Docker——你需要知道的Docker进阶知识二

Docker 进阶之镜像分层详解

Docker 进阶之镜像分层详解

详解Docker——你需要知道的Docker进阶知识五

容器技术Docker K8s 51 容器镜像服务(ACR)详解-进阶

Docker 容器镜像制作指令详解