文章目录
一、概述
1.1 出现的原因
常见问题:
- 自己电脑运行,别人就运行不起来,这给运维带来了十分大的考验。
- 环境配置十分麻烦、费时费力,且不能跨平台。
发布一个项目时不单单生成一个jar或war,而是希望项目带着环境一起打包。当开发人员想要运行某一项目时,下载后直接运行。比如,java发布一个安卓程序:java - apk - 发布(应用商店) - 张三使用apk - 安装即可用。
使用Docker后,java发布一个项目:java - jar (环境) - 打包项目带上环境(镜像) - ( Docker仓库:商店) - 下载发布的镜像 - 直接运行即可
Docker给以上的问题,提出了解决方案。
Docker的核心思想是打包装箱,每个箱子都是互相隔离的,通过各级机制,可以将服务器利用到极致。
1.2 虚拟机与Docker
虚拟机:属于虚拟化技术。
Docker:容器技术,也是一种虚拟化技术。
Vmware:使用linux原生镜像,就相当于一台电脑。多个虚拟机之间互相独立,虚拟机体积十分大,需要几个G的磁盘空间;开启速度缓慢,需要几分钟。
docker:不需要linux镜像,直接运行最核心的镜像环境(如jdk、mysql等),体积小、启动快。
1.3 官网
官网:https://www.docker.com/
文档:https://docs.docker.com/get-started/
仓库:https://hub.docker.com/
1.4 应用
虚拟机技术
缺点:占用资源多、冗余步骤多、启动慢
容器化技术
容器化技术不是模拟一个完整的操作系统。
Docker与虚拟机:
- 传统虚拟机,虚拟出一条硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件
- 容器内的应用直接运行在宿主机的内容,容器是没有自己的内核的,也没有虚拟我们的硬件,所以就轻便了。
- 每个容器间是互相隔离,每个容器内都有一个属于自己的文件系统,不影响。
应用更快速的交付和部署
传统:一堆帮助文档,安装程序
Docker:打包镜像、发布测试、一键运行
更便捷的升级和扩缩容
使用了Docker之后,我们部署应用就和搭积木一样!
项目打包为一个镜像,扩展服务器A、服务器B。
更简单的系统运维
在容器化之后,我们的开发,测试环境都是高度一致的。
更高效的计算资源利用
Docker是内核级别的虚拟化,可以在一个物理机上可以运行很多的容器实例。服务器的性能可以被压榨到极致。
二、基本组成
镜像(image):
docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,tomcat镜像 --> run --> tomcat01容器(提供服务器),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)。
容器(container):
Docker利用容器技术,独立运行一个或者一个组应用,通过镜像来创建的。
启动,停止,删除,基本命令!
目前就可以把这个容器理解为就是一个简易的linux系统。
仓库(repository):
仓库就是存放镜像的地方!
仓库分为公有仓库和私有仓库!
Docker Hub (默认是国外的),需要配置镜像加速。
国内有阿里等。
三、安装
在CentOS上进行安装,保证CentOS版本在7或以上。
官网安装教程:https://docs.docker.com/engine/install/centos/
参考官方文档的简化安装过程:
步骤1:卸载(保证系统中不包含docker)
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
步骤2:创建仓库、设置仓库地址
sudo yum install -y yum-utils
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
步骤3:安装Docker引擎
sudo yum install docker-ce docker-ce-cli containerd.io
步骤4:启动Docker
sudo systemctl start docker
步骤5:运行helloword镜像 测试
sudo docker run hello-world
步骤6:设置开机自启
sudo systemctl enable docker
步骤7:配置镜像加速,阿里云
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://frz3dfut.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
阿里云镜像加速器:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
卸载dokcer
步骤1:卸载docker引擎
sudo yum remove docker-ce docker-ce-cli containerd.io
步骤2:卸载镜像、容器
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
四、运行原理
在刚刚的安装过程中,运行的hello-world的原理如下图。
Docker是什么工作的?
Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上。通过Socket从客户端访问!
DockerServer接收到Docker-Client 的指令,就会执行这个命令!
Docker为什么比VM快?
- Docker有着比虚拟机更少的抽象层。
- docker 利用的是宿主机的内核,vm需要Guest OS.
新建一个容器的时候, docker不需要想虚拟机一样重新加载一个操作系统内核,避免引导。虛拟机是加载GuestOS,分钟级别的,而docker是利用宿主机的操作系统吗,省略了这个复杂的过程,秒级!
五、常用命令
帮助文档:https://docs.docker.com/reference/
命令详细介绍,请看官方帮助文档。
5.1 帮助命令
查看版本信息:docker version
显示系统信息:docker info
帮助命令:docker 命令 help
5.2 镜像命令
查看主机上所有的镜像:docker images
搜索镜像:docker search 镜像名
下载镜像:docker pull 镜像名
删除镜像:docker rmi 镜像名
5.3 容器命令
说明:有了镜像才可以创建容器,linux,下载centos镜像来测试。
docker pull centos
新建容器并启动:
docker run [可选参数] image
# 参数说明
--name="Name" 容器名字,用来区分容器,如 tomcat1 tomcat2
-d 后台方式运行
-it 交互方式运行
-p(小写) 指定容器端口 -p 主机端口:容器端口
-P(大写) 随机指定端口
启动并进入容器:docker run -it centos /bin/bash
退出容器:exit
列出运行中的容器:docker ps
删除容器:docker rm 容器id
启动容器:docker start 容器id
重启容器:docker restart 容器id
停止容器:docker stop 容器id
强制停止容器:docker kill 容器id
5.4 其他命令
后台启动容器:docker run -d 容器名
查看日志:docker logs -tf --tail 条数 容器名
查看容器进程:docker top 容器id
查看元数据:docker inspect 容器id
进入当前正在运行的容器,开启一个新的终端:docker exec -it 容器id /bin/bash
进入当前正在运行的容器,继续正在执行的终端:docker attach 容器id
从容器内拷贝文件到主机上:docker cp 容器id:容器内路径 目的主机路径
六、安装举例
6.1 安装nginx
步骤1:搜索nginx镜像
docker search nginx
[root@localhost1 bin]# docker search nginx
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
nginx Official build of Nginx. 16036 [OK]
jwilder/nginx-proxy Automated Nginx reverse proxy for docker con… 2104 [OK]
richarvey/nginx-php-fpm Container running Nginx + PHP-FPM capable of… 820 [OK]
jc21/nginx-proxy-manager Docker container for managing Nginx proxy ho… 299
linuxserver/nginx An Nginx container, brought to you by LinuxS… 161
tiangolo/nginx-rtmp Docker image with Nginx using the nginx-rtmp… 148 [OK]
jlesage/nginx-proxy-manager Docker container for Nginx Proxy Manager 147 [OK]
alfg/nginx-rtmp NGINX, nginx-rtmp-module and FFmpeg from sou… 112 [OK]
nginxdemos/hello NGINX webserver that serves a simple page co… 81 [OK]
privatebin/nginx-fpm-alpine PrivateBin running on an Nginx, php-fpm & Al… 61 [OK]
nginx/nginx-ingress NGINX and NGINX Plus Ingress Controllers fo… 59
nginxinc/nginx-unprivileged Unprivileged NGINX Dockerfiles 56
nginxproxy/nginx-proxy Automated Nginx reverse proxy for docker con… 32
staticfloat/nginx-certbot Opinionated setup for automatic TLS certs lo… 25 [OK]
nginx/nginx-prometheus-exporter NGINX Prometheus Exporter for NGINX and NGIN… 22
schmunk42/nginx-redirect A very simple container to redirect HTTP tra… 19 [OK]
centos/nginx-112-centos7 Platform for running nginx 1.12 or building … 16
centos/nginx-18-centos7 Platform for running nginx 1.8 or building n… 13
bitwarden/nginx The Bitwarden nginx web server acting as a r… 12
flashspys/nginx-static Super Lightweight Nginx Image 11 [OK]
mailu/nginx Mailu nginx frontend 10 [OK]
webdevops/nginx Nginx container 9 [OK]
sophos/nginx-vts-exporter Simple server that scrapes Nginx vts stats a… 7 [OK]
ansibleplaybookbundle/nginx-apb An APB to deploy NGINX 3 [OK]
wodby/nginx Generic nginx 1 [OK]
也可以去Docker Hub上搜索,看到详细的信息。
步骤2:拉取nginx
docker pull nginx
[root@localhost1 bin]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
a2abf6c4d29d: Pull complete
f3409a9a9e73: Pull complete
9919a6cbae9c: Pull complete
fc1ce43285d7: Pull complete
1f01ab499216: Pull complete
13cfaf79ff6d: Pull complete
Digest: sha256:366e9f1ddebdb844044c2fafd13b75271a9f620819370f8971220c2b330a9254
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
步骤3:启动nginx
docker run -d --name nginx01 -p 80:80 nginx
[root@localhost1 bin]# docker run -d --name nginx01 -p 80:80 nginx
bae37dccb8b6f6bf2aca9b9f93ba03703885fa80a50a896dc441834ac38a9a99
步骤4:测试nginx
curl localhost:80
[root@localhost1 bin]# curl localhost:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>
步骤5:进入容器
docker exec -it nginx01 /bin/bash
[root@localhost1 bin]# docker exec -it nginx01 /bin/bash
root@bae37dccb8b6:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
6.2 安装tomcat
用完即删:下载之后启动,关闭之后删除。
docker run -it --rm tomcat:9.0
6.3 部署es
暴露的端口很多、十分耗内存、数据一般需要放置到安全目录挂载。
七、可视化
portainer
docker run -d -p 8000:8000 -p 9443:9443 --name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
cr.portainer.io/portainer/portainer-ce:2.9.3
访问:https://ip:9443
八、镜像原理
8.1 镜像加载原理
8.2 镜像分层
8.3 commit镜像
提交容器称为一个新的副本:docker commit
docker commit -m="描述信息" -a="作者" 容器id 目标镜像名: [TAG]
1、启动一个默认的tomcat
2、发现这个默认的tomcat是没有webapps应用, 镜像的原因,官方的镜像默认webapps下面是没有文件的
3、我自己拷贝进去了基本的文件
4、将我们操作过的容器通过commit提交为一个镜像! 我们以后就使用我们修改过的镜像即可,这就是我们自己的一个修改的镜像
九、容器数据卷
9.1 原理
将应用和环境打包成一个镜像。
如果数据都在容器中,那么我们容器删除,数据就会丢失!需求:数据可以持久化。
MySQL,容器删了, 删库跑路!需求:MySQL数据可以存储在本地。
容器之间可以有一个数据共享的技术,Docker 容器中产生的数据,同步到本地。
这就是卷技术,目录的挂载,将我们容器内的目录,挂载到Linux上面。
总结一句话:容器的持久化和同步操作,容器间也是可以数据共享的。
当容器被删除时,挂载到本地的数据卷依旧存在。
9.2 使用
方式一:直接使用命令挂载 -v
docker run -it -v 主机目录:容器内目录
启动后,可通过docker inspect 容器id查看到:
好处:我们以后修改只需要在本地修改即可,容器内会自动同步。
9.3 安装mysql
9.3.1 安装
步骤1:安装mysql
docker pull mysql:5.7
步骤2:创建实例并启动
docker run -p 3306:3306 --name mysql \
-v /mydata/mysql/log:/var/log/mysql \
-v /mydata/mysql/data:/var/lib/mysql \
-v /mydata/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql:5.7
启动成功后会返回一串id,输入docker ps
可以查看docker当前运行的容器。
可选:设置开机自动启动
sudo docker update mysql --restart=always
9.3.2 说明
docker容器文件挂载与端口映射
-
docker run
:启动容器 -
docker中每一个容器都可以看作一个完整的linux系统。输入命令
docker exec -it mysql /bin/bash
,进入容器内部。再次输入ls
,查看当前目录,与 linux的目录结构基本一样。(exit;
退出容器)
-
-p 3306:3306
:在MySql容器中3306是mysql的端口,需要将mysql容器的端口映射到linux内,相当于访问linux的3306端口,就可以访问MySql容器的3306端口。 -
--name
:给容器起一个名字。 -
-v
:目录挂载。 -
-v /mydata/mysql/log:/var/log/mysql
:在linux目录下创建mydata/mysql/log
目录,将MySql容器下的var/log/mysql
目录与之挂载。就是MySql容器内var/log/mysql
目录下的资源可在Linux的mydata/mysql/log
目录下查看到。一处修改,另一处同时发生改变。
9.3.3 修改配置
步骤1:创建配置文件
cd /mydata/mysql/conf
vi my.cnf
步骤2:编写配置文件
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
在vi内,点击右键粘贴。
:wq
保存退出
注意:配置文件写错的话,就无法启动MySQL了。
步骤3:重启mysql容器
docker restart mysql
启动mysql容器的命令为:docker start mysql
9.4 具名、匿名挂载
匿名挂载:-v 容器内路径
具名挂载:-v 卷名:容器内路径
指定路径挂载:-v 宿主机路径(以“/”开头):容器内路径
所有的docker容器内的卷,没有指定目录的情况下都是在/var/lib/docker/volumes/xxxx/_data
我们通过具名挂载可以方便的找到我们的一个卷,大多数情况在使用的具名挂载。
9.5 初识Dockerfile
Dockerfile就是用来构建docker镜像的构建文件,使用命令脚本。
通过这个脚本可以生成镜像,镜像是一层一层的,脚本一个个的命令,每个命令都是一层。
创建脚本 dockerfile1:以centos为基础,挂载两个目录volume1,volume2,输出----end----
,进入目录/bin/bash
FROM centos
VOLUME ["volume1","volume2"]
CMD echo "----end----"
CMD /bin/bash
通过脚本生成镜像:
docker build -f dockerfile1 -t my/centos:1.0 .
启动镜像:
这个卷和外部一定有一个同步的目录,匿名挂载。
查看容器元数据: docker inspect 容器id
,可以查看匿名挂载的目录。
9.6 数据卷容器
多个mysql同步数据:
启动2个容器:
启动第1个容器:
docker run -it --name docker01 镜像id
[root@localhost1 docker-test-volume]# docker run -it --name docker01 5071b1ce59c7
[root@7e922b7b1c87 /]# ls -l
total 0
lrwxrwxrwx. 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x. 5 root root 360 Dec 31 02:30 dev
drwxr-xr-x. 1 root root 66 Dec 31 02:30 etc
drwxr-xr-x. 2 root root 6 Nov 3 2020 home
lrwxrwxrwx. 1 root root 7 Nov 3 2020 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Nov 3 2020 lib64 -> usr/lib64
drwx------. 2 root root 6 Sep 15 14:17 lost+found
drwxr-xr-x. 2 root root 6 Nov 3 2020 media
drwxr-xr-x. 2 root root 6 Nov 3 2020 mnt
drwxr-xr-x. 2 root root 6 Nov 3 2020 opt
dr-xr-xr-x. 201 root root 0 Dec 31 02:30 proc
dr-xr-x---. 2 root root 162 Sep 15 14:17 root
drwxr-xr-x. 11 root root 163 Sep 15 14:17 run
lrwxrwxrwx. 1 root root 8 Nov 3 2020 sbin -> usr/sbin
drwxr-xr-x. 2 root root 6 Nov 3 2020 srv
dr-xr-xr-x. 13 root root 0 Dec 20 02:26 sys
drwxrwxrwt. 7 root root 171 Sep 15 14:17 tmp
drwxr-xr-x. 12 root root 144 Sep 15 14:17 usr
drwxr-xr-x. 20 root root 262 Sep 15 14:17 var
drwxr-xr-x. 2 root root 6 Dec 31 02:30 volume1
drwxr-xr-x. 2 root root 6 Dec 31 02:30 volume2
exit
启动第2个容器:
docker run -it --name docker02 --volumes-from docker01 镜像id
[root@localhost1 docker-test-volume]# docker run -it --name docker02 --volumes-from docker01 5071b1ce59c7
[root@e1e59623a90a /]# ls -l
total 0
lrwxrwxrwx. 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x. 5 root root 360 Dec 31 02:38 dev
drwxr-xr-x. 1 root root 66 Dec 31 02:38 etc
drwxr-xr-x. 2 root root 6 Nov 3 2020 home
lrwxrwxrwx. 1 root root 7 Nov 3 2020 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Nov 3 2020 lib64 -> usr/lib64
drwx------. 2 root root 6 Sep 15 14:17 lost+found
drwxr-xr-x. 2 root root 6 Nov 3 2020 media
drwxr-xr-x. 2 root root 6 Nov 3 2020 mnt
drwxr-xr-x. 2 root root 6 Nov 3 2020 opt
dr-xr-xr-x. 203 root root 0 Dec 31 02:38 proc
dr-xr-x---. 2 root root 162 Sep 15 14:17 root
drwxr-xr-x. 11 root root 163 Sep 15 14:17 run
lrwxrwxrwx. 1 root root 8 Nov 3 2020 sbin -> usr/sbin
drwxr-xr-x. 2 root root 6 Nov 3 2020 srv
dr-xr-xr-x. 13 root root 0 Dec 20 02:26 sys
drwxrwxrwt. 7 root root 171 Sep 15 14:17 tmp
drwxr-xr-x. 12 root root 144 Sep 15 14:17 usr
drwxr-xr-x. 20 root root 262 Sep 15 14:17 var
drwxr-xr-x. 2 root root 6 Dec 31 02:30 volume1
drwxr-xr-x. 2 root root 6 Dec 31 02:30 volume2
在docker01的volume1内添加文件,docker02的volume1内会同步。
删除docker01容器,docker02依然可以访问文件。
两个mysql可以实现数据的共享,因为它们挂载的目录相同,但是同一时刻只能启动一个容器。
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器为之。
一旦持久化到本地,数据不会删除。
十、DockerFile
10.1 介绍
用来构建docker镜像的文件,命令参数脚本。
构建步骤:
- 编写dockerfile文件
- docker build 构建一个镜像
- docker run 运行镜像
- docker push 发布镜像(DockerHub、阿里云镜像仓库)
官方实现方式:
https://hub.docker.com/_/centos
打开后,是一个dockerfile文件。
10.2 基础知识
1、每个保留关键字(指令)都是必须是大写字母
2、执行从上到下顺序执行
3、#表示注释
4、每一个指令都会创建提交一个新的镜像层,并提交。
dockerfile是面向开发的,以后发布项目,做镜像,需要编写dockerfile文件,这个文件十分简单。
DockerFile:构建文件,定义了一切的步骤、源代码
Dockerlmages:通过DockerFile构建生成的镜像,最终发布和运行的产品,原来使用的是jar war
Docker容器:就是镜像运行起来提供服务器
10.3 指令
FROM:基础镜像,一切从这里开始构建
MAINTAINER:镜像的作者,姓名+邮箱
RUN:镜像构建的时候需要的命令
ADD:复制文件,会自动解压
WORKDIR:镜像的工作目录
VOLUME:设置卷,挂载主机目录
EXPOSE:指定暴露端口
CMD:指定容器启动时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT:指定容器启动时候要运行的命令,可以追加命令
ONBUILD:当构建一个被继承DockerFile这个时候会运行ONBUILD指令,触发指令。
COPY:类似ADD,将文件拷贝到镜像
ENV:构建的时候设置环境变量
可参考:https://blog.csdn.net/y472360651/article/details/81289141
10.4 实战
Docker Hub镜像基本都是从基础镜像scratch开始的。
…