Docker入门

2023-12-13 04:03:13

1、Docker概述

纯物理服务器部署
在这里插入图片描述

  • 部署非常慢:购买服务器 --> 部署操作系统 --> 安装应用,这仅仅是对于一台服务器的流程。如果对于集群,有多台服务器,部署就会非常慢
  • 成本非常高:服务器成本高
  • 资源浪费:如果每台服务器的配置都比较高,但是仅仅运行一个应用程序。那就造成资源浪费
  • 难于迁移和扩展:迁移时候,需要把服务器的所有配置流程重新造作一边。
  • 可能会被限定硬件厂商:应用程序如果是运行在A操作系统,那怎么配置在具有B操作系统的服务器上

很多时候,我们只想要一个单独的执行环境,而不需要费劲虚拟出一个完整的计算机。比如仅仅希望同时使用MySQL5.7和5.8。
虚拟出一台计算机的成本,远高于只虚拟出一个隔离的程序运行环境。容器技术思想正是基于此。
在这里插入图片描述
举个例子
在这里插入图片描述

2、Docker基础组件

Docker的核心是运行镜像,生成对应的容器。
在这里插入图片描述

核心组件:

  • image镜像,镜像是一个只读模板,用于构建容器,即我们将应用程序运行所需的环境,打包为镜像文件。也可以通过dockerfile文本描述镜像的内容。
  • container容器,是镜像运行的实例,我们的应用程序就运行在容器中
  • Registry镜像仓库,用于保存镜像文件,提供上传下载镜像文件,作用好比GitHub
  • dockerfile,将所部署项目的操作,写成部署脚本dockerfile。且该脚本还能构建出镜像文件

3、Docker的基础命令

以nginx web为例子,如果是单台服务器上配置80端口的流程是:
1)开启服务器
2)在服务器上安装好运行nginx所需的依赖
3)安装nginx
4)修改nginx配置文件
5)启动nginx
6)客户端访问nginx

显然,如果是多台服务器,那要一一配置十分麻烦。而在Docker下,只需三个步骤
1)获取镜像
2)运行镜像,生成容器
3)客户端访问

具体流程是:
1)检索所需的镜像文件是否存在

docker search nginx

在这里插入图片描述
2)获取镜像:从配置好的Docker镜像站中,拉取nginx镜像

docker pull nginx

在这里插入图片描述

3)查看本地的Docker镜像有哪些

docker image ls
# 或者 docker images

在这里插入图片描述
4)运行该nginx镜像:运行出具体的容易,然后这个容器就跑着一个nginx服务

docker run -d -p 80:80 nginx

-d:后台运行容器
-p 80:80:端口映射,宿主机端口:容器内端口,即若访问宿主机的这个端口,也就访问到了容器内的端口
在这里插入图片描述

5)查看容器是否在线运行
在这里插入图片描述

6)服务端访问80端口

在这里插入图片描述
7)停止运行的容器

docker stop 容器ID/名字

在这里插入图片描述

4、Docker生命周期详解

在这里插入图片描述

5、docker镜像

5.1 利用docker使用不同的操作系统

我们一直以来使用VMware虚拟机安装的系统,是一个完整的系统文件,包括两部分

  • linux内核,作用是提供操作系统的基本功能,以及和机器硬件交互
  • Ubuntu / Centos等发行版,作用是提供软件功能,利用Ubuntu 的apt安装包管理,Centos的yum安装包管理

因此,一个完整的系统,是由linux的内核+发行版,才组成了一个可以使用的完整的系统。就好比基于安卓系统,小米、华为等在上面开发了自己的系统。
在这里插入图片描述

是否有一个办法,可以灵活的替换发行版,让我们使用不同的系统?
那么docker就实现了这个功能,技术手段就是docker images
利用docker容器,可以获取不同的发行版镜像,然后基于该镜像,运行出各种容器
在这里插入图片描述
具体操作流程:

1)利用docker获取不同的发行版镜像

docker pull ubuntu
docker pull centos

在这里插入图片描述

2)确认宿主机的发行版本

# Ubuntu命令
cat /etc/lsb-release 

在这里插入图片描述

3)运行centos发行版,即运行容器,且进入容器内

docker run -it 5d0da3dc9764 bash

参数解释:
-i交互式命令操作
-t 开启一个终端
5d0da3dc9764 是镜像的id
bash 进入容器后,执行的命令
在这里插入图片描述3)查看容器内的发行版

# centos命令
cat /etc/redhat-release 

在这里插入图片描述
4)退出

exit

5.2 docker镜像原理

在这里插入图片描述

docker镜像不包含linux内核,和宿主机共用。如果想要定义一个mysql 5.6镜像,我们会这么做

  • 获取基础镜像,选择一个发行版平台 (ubutu,centos)
  • 在centos镜像中安装mysql 5.6软件
  • 导出镜像,可以命名为mysql 5.6镜像文件

从这个过程,我们可以感觉出这是一层一层的添加的,docker镜像的层级概念就出来了,底层是centos镜像,上层是mysql 镜像,centos镜像层属于父镜像。
在这里插入图片描述

Docker镜像是在基础镜像之后,然后安装软件,配置软件,添加新的层,构建出来。
这种现象在学习dockerfile构建时候,更为清晰。

# 进入容器内部
docker exec -it 容器id bash

Docker为什么分层镜像?
镜像分享一大好处就是共享资源,例如有多个镜像都来自于同一个base镜像,那么在docker host只需要存储一份base镜像。
内存里也只需要加载一份host,即可为多个容器服务
在这里插入图片描述

即使多个容器共享一个base镜像,某个容器修改了base镜像的内容,例如修改/etc/下配置文件,其他容器的/etc/下内容是不会被修改的,修改动作只限制在单个容器内,这就是容器的写入时复制特性 (Copy-on-write)

可写的容器层
当容器启动后,一个新的可写层被加载到镜像的顶部。这一层通常被称为容器层。容器层的下面都称为镜像层
在这里插入图片描述

所有对容器的修改动作,都只会发生在 容器层 里,只有 容器层 是可写的,其余镜像层 都是只读的。在这里插入图片描述
只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改

这样就解释了我们前面提出的问题: 容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改所以镜像可以被多个容器共享

6、Docker镜像管理

6.1 获取镜像

1、查看docker镜像的存储路径

zxm@ubuntu:~$ docker info | grep Root
 Docker Root Dir: /var/lib/docker

查看具体内容

ls /var/lib/docker/image/overlay2/imagedb/content/sha256 -l

在这里插入图片描述
2、使用不同的镜像,生成容器

docker run -it -rm centos bash

-it开启一个交互式的终端
--rm容器退出时删除该容器

6.2 查看镜像

# 查看所有镜像信息
docker images 
# 仅查看ubuntu
docker images ubuntu
# 只列出id
docker images -q	
# 格式化输出,输出id和Repository
docker images --format "{{.ID}}--{{.Repository}}"
# 以表格形式输出
docker images --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
# 查看镜像的详细信息
docker image inspect 镜像id(前三位即可)

# 在docker hub中搜索镜像
docker search 镜像名

# 查看容器内进程信息的命令
docker top 容器id
# 查看容器内资源
docker stats 容器id
# 查看容器的具体信息
docker inspece容器id

在这里插入图片描述

6.3 删除镜像

根据镜像的id、名字、摘要等删除。

docker rmi hello-world

需要注意的是,被删除的镜像,不得有依赖的容器记录
在这里插入图片描述
此时需要先删除对应的容器记录

docker rm cba633bf1589

再删除容器
在这里插入图片描述

6.4 导出导入镜像

# 导出并压缩镜像到/opt目录下
docker image save centos > /opt/centos.tgz
# 导入/opt目录下的镜像
docker image load -i /opt/centos.tgz

在这里插入图片描述

6.5 容器管理

docker run 等于创建+启动
docker run 镜像名,如果镜像不存在本地,则会在线去下载该镜像

注意:

  • 容器内的进程必须处于前台运行状态,否则容器就会直接退出。也就是如果自己部署一个容器运行,命令不得后台运行,需要前台运行。
  • 如果容器内,什么事也没做,容器也会挂掉。也就是说,容器内必须有一个进程在前台运行。

具体命令:
1)docker run centos
这个写法,会产多多独立的容器记录,且容器内没有程序在跑,因此挂了。只会增加多条容器记录
在这里插入图片描述

2)运行容器,且进入容器内,且在容器内执行某个命令
在这里插入图片描述
3)开启一个容器,让它帮你运行某个程序,属于前台运行,会卡主一个终端

docker run centos ping baidu.com

4)运行一个活着的容器,docker ps可以看到的容器
-d :让容器在后台跑着 (针对宿主机而言)
返回容器id

docker run -d centos ping baidu.com

还可以增加其他参数

docker run -d --rm --name pybaidu centos ping baidu.com

--rm:容器挂掉之后,自动删除记录(删除的是docker ps -a 里面查看的记录)
--name:给容器起个名字

5)查看容器日志,刷新日志

docker logs -f 容器id
docker logs 容器id | tail -5

6)进入到一个正在运行的容器空间内

docker exec -it 容器id bash

7)查看容器的详细信息,用于高级的调试

docker container inspect 容器id

8)容器的端口映射
后台运行nginx容器,且起个名字,且端口映射宿主机的85端口,访问到容器内的80端口

docker run -d --name zxm_nginx -p 85:80 nginx

查看容器的端口转发情况

docker port 容器id

9)容器的提交
运行基础的centos,在容器内安装vim,然后提交新的镜像。
新的镜像再运行出的容器,默认就携带vim了

docker run -it centos
# 进入centos后,安装vim
yum install vim
# 退出
exit

# 提交容器
docker commit 容器id 新的镜像名

7、Dockerfile

7.1 Dockerfile基础命令

镜像是多层存储,每一层在前一层的基础上进行修改;
容器也是多层存储,以镜像为基础层,在其基础上加一层作为容器运行时的存储层

创建镜像的两个方法

  • 手动修改容器内容,然后docker commit提交容器为新的镜像
  • 通过在dockerfile中定义一系列的命令和参数构成的脚本,然后这些命令应用于基础镜像,依次添加层最终生成一个新的镜像。极大的简化了部署工作。

dockerfile主要组成部分

  • 基础镜像信息 FROM centos:6.8

  • 制作镜像操作指令RUN yum insatll openssh-server -y

  • 容器启动时执行指令CMD["/bin/bash"]

  • FROM 这个镜像的妈妈是谁?(指定基础镜像)

  • MAINTAINER 告诉别人,谁负责养它?(指定维护者信息,可以没有)

  • RUN 你想让它干啥 (在命令前面加上RUN即可)

  • ADD 添加宿主机的文件到容器内,还多了一个自动解压的功能

  • COPY 作用和ADD是一样的,都是拷贝宿主机的文件到容器内,COPY就是仅仅拷贝

  • WORKDIR 我是cd,今天刚化了妆 (设置当前工作目录)

  • VOLUME 给它一个存放行李的地方 (设置卷,挂载主机目录)

  • EXPOSE它要打开的门是啥(指定对外的端口),在容器内暴露一个端口 EXPORT 80

  • CMD 奔跑吧,兄弟! (指定容器启动后的要干的事情)

7.2 Dockerfile实践–重定向nginx

需求,通过Dockerfile,构建nginx镜像。运行容器后,生成的页面是“中华人民共和国是工人阶级领导的、以工农联盟为基础的人民民主专政的社会主义国家”

1、创建Dockerfile(文件名必须是这个)

mkdir docker-learn

vim Dockerfile

# 文件内写入以下内容
FROM nginx
RUN echo '<meta charset=utf8>中华人民共和国是工人阶级领导的、以工农联盟为基础的人民民主专政的社会主义国家.' > /usr/share/nginx/html/index.html

2、构建Dockerfile

docker build .

3、修改镜像名字

docker tag 2b7e8ce80df1 my-nginx

在这里插入图片描述
当然,也可以将构建的时候同时修改名字

docker build -t 'my-nginx' .

4、运行该镜像

docker run -d -p 80:80 my-nginx

5、客户端运行该端口

7.3 命令详解

7.3.1 COPY

1、COPY指令从宿主机复制文件/目录到新的一层镜像内

copy 宿主机文件目录 镜像内目录

2、支持多个文件,以及通配符形式复制,语法要满足Golang的filepath.Match

copy zxm* /tmp/cc?.txt. /home/

3、COPY指令能够保留源文件的元数据,如权限,访问时间等等,这点很重要

7.3.2 ADD

特性和COPY基本一致,不过多了些功能
1、源文件是一个URL,此时docker引擎会下载该链接、放入目标路径,且权限自动设为600,若这不是期望结果,还得增加一层RUN指令
2、源文件是一个URL,且是一个压缩包,不会自动解压,也得单独用RUN指令解压
3、源文件是一个压缩文件,且是gzip,bzip2,xz,tar情况,ADD指令会自动解压缩该文件到目标路径

7.3.3 CMD

用法,注意是双引号

CMD["参数1""参数2"]

在指定了entrypoint指令后,用CMD指定具体的参数

docker不是虚拟机,容器就是一个进程,既然是进程,那么程序在启动的时候需要指定些运行参数,这就是CMD指令作用
例如
1)centos镜像默认的CMD是["/bin/bash"],直接docker run -it centos会直接进入bash解释器.
2)["cat","/etc/os-release"],等价于命令行的直接操作 docker run -t centos cat /etc/os-releasea

CMD运行she11命令,也会被转化为shel1形式
例如CMD echo $PATH
会被转化为CMD ["sh","-c","echo $PATH"]

CMD 用于容器内运行程序的坑
把宿主机安装,启动nginx的理念放入到dockerfile

1、RUN yum install nginx
2、RUN 配置文件修改 sed

# 这是错误的,容器是启动不了。因为容器内的程序必须是前台运行
3、RUN systemctl start nginx

这里要注意的是,docker不是虚拟机的概念,虚拟机里的程序运行,基本上都是在后台运行,利用systemctl运行,但是容器内没有后台进程的概念,必须在前台运行。
容器就是为了主进程而存在的,主进程如果退出了,容器也就失去意义,自动退出。

例如刚才的问题

CMD systemctl start nginx

这样的写法是错误的,容器会立即退出。因为systemctlstart nginx是希望以守护进程形式启动nginx,且CMD命令会转化为

CMD ["sh","-c","systemctl start nginx"]

这样的命令主进程是sh解释器,执行完毕后立即结束了,因此容器也就退出了。
因此正确的做法应该是

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

7.3.4 ENTRYPOINT

作用和CMD一样,都是在指定容器启动程序以及参数.
当指定了ENTRYPOINT之后,CMD指令的语义就有了变化,而是吧CMD的内容当作参数传递给ENTRYPOINT指令

1、准备一个Dockerfile

FROM ubuntu
RUN apt-get update && apt-get install -y curl
CMD ["curl", "-s", "http://ipinfo.io/ip"]

2、构建镜像

docker build .

3、检查镜像并修改名字

docker images
docker tag 93ef97d8f86f ubuntu-curl

在这里插入图片描述

4、运行镜像,生成容器记录,没有前台运行,因此立即挂了

docker run ubuntu-curl

5、上述运行正确,但是想再传入一个参数,该怎么办?
比如命令行输入curl -s http://ipinfo.io/ip -I,获得如下结果
在这里插入图片描述
我想通过使用docker run ubuntu-curl -I,但是报错。发现是无法直接传入参数的,因为该形式是覆盖镜像中的cmd。就好比把该docker镜像,当做一个环境,去执行后面的命令
在这里插入图片描述
6、想要正确的给容器传入一个 -I 参数该怎么办
方法1:docker run ubuntu-curl curl -s http://ipinfo.io/ip -I,但是每次需要把cmd里完整的命令敲一遍。

方法2:修改Dockerfile,不用CMD,用ENTRYPOINT

FROM ubuntu
RUN apt-get update && apt-get install -y curl
ENTRYPOINT ["curl", "-s", "http://ipinfo.io/ip"]

然后重新构建

docker build .
docker tag 09af558344b2 ubuntu-curl-new
docker run ubuntu-curl-new -I

7.3.5 ENV

ENV NAME="zxm"
ENV AGE="18"
ENV MYSQL VERSION=5.6

后续所有的操作,通过$NAME 就可以直接获取变量值

ARG和ENV一样,用于设置环境变量
区别在于ENV 无论是在镜像构建时,还是容器运行,该变量都可以使用
ARG只是用于构建镜像需要设置的变量,容器运行时就消失了

7.3.6 VOLUME

容器在运行时,应该保证在存储层不写入任何数据,运行在容器内产生的数据,我们推荐是挂载,写入到宿主机上,进行维护。

VOLUME /data

将容器内的/data文件夹 ,在容器运行时,该目录自动挂载为匿名卷,任何向该目录中写入数据的操作,都不会被容器记录,保证的容器存储层无状态理念

Dockerfile文件

FROM centos

VOLUME ["/data1","/data2"]

该容器运行时候,这2个目录自动和宿主机的目录做好映射关系

docker build .
docker inspect 5b12af9d63e9  # 查看详细信息

容器数据挂载的方式,除了通过dockerfile,指定VOLUME目录。
还可以通过dockerrun-v 参数,直接设置需要映射挂载的目录

7.3.7 EXPOSE

指定容器运行时对外提供的端口服务,
帮助使用该镜像的人,快速理解该容器的一个端口业务

docker port #查看容器端口
docker run -p #宿主机端口: 容器端口
docker run -P # 作用是随机宿主机端口: 容器内端口

7.3.8 WORKDIR

用于在dockerfile中,目录的切换,更改工作目录

WORKDIR /opt

7.3.9 USER

用于改变环境,用于切换用户

USER root
USER zxm

推荐一个零声学院的C++服务器开发课程,个人觉得老师讲得不错,
分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容
点击立即学习:C/C++后台高级服务器课程

文章来源:https://blog.csdn.net/Ricardo2/article/details/134777211
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。