Docker为什么火,因为十分的轻巧。
Docker是基于Go语言开发的。
虚拟机技术:
容器化技术:容器化技术不是模拟一个完整的操作系统。
docker镜像好比是一个模版,可以通过这个模版来创建容器服务,mysql镜像==>run==>mysql01容器(提供服务),通过这个镜像可以创建多个容器。
docker利用容器技术,独立运行一个或者一组应用。通过镜像来创建的。
基本命令有启动、停止、删除等。
目前可以把容器理解为就是一个简易的Linux系统。
仓库就是存放镜像的地方。仓库分为公有仓库和私有仓库。默认是国外的仓库(DockerHub),国内有阿里云等(配置镜像加速)
uname -r
sudo cat /etc/os-release
sudo apt-get remove docker docker-engine docker.io containerd runc
sudo apt-get update
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
上面是官网提供的,但是速度很慢,建议使用阿里云的GPG Key。
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
上面是官网提供的,但是速度很慢,建议使用阿里云提供的。
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
$(lsb_release -cs) stable"
注意:添加错了可以用以下命令删除
#查询keyid,下图
sudo apt-key list
#keyid 就是9DC8那一串
sudo apt-key del <keyid>
#加参数-r可以移除
sudo add-apt-repository -r "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
这样就可以安装Docker Engine和containerd的最新版本
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
如果要安装指定版本的Docker引擎,在repo中列出可用版本,然后选择安装
apt-cache madison docker-ce
sudo apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io
添加后,以后就可以不用 sudo 运行 docker 了。
sudo gpasswd -a ${
USER} docker
newgrp - docker
sudo service docker restart
docker ps
首先启动Docker
systemctl start docker
查看Docker版本来判断是否安装成功
docker version
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://eko3tl65.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
Docker是一个Client·Server结构的系统,Docker的守护进程运行在主机上,通过Socket从客户端访问,DockerServer接受到DockerClient的指令,就会去执行这个指令。
# 显示docker的版本信息
docker version
# 显示docker的系统信息 包括镜像和容器的数量
docker info
# 帮助命令
docker 命令 --help
帮助文档地址:官方文档
查看所有本地的主机上的镜像
malulu@malulu:~/桌面$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 519e12e2a84a 4 days ago 133MB
hello-world latest d1165f221234 5 weeks ago 13.3kB
# 解释
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的ID
CREATED 镜像的创建时间
SIZE 镜像的大小
# 可选项
-a, --all # 列出所有镜像
-q, --quiet # 只显示镜像的ID
搜索镜像
# 可选项
--filter=STARS=3000 # 搜索出来的镜像就是STARS大于3000的
下载镜像
# 下载镜像
docker pull 镜像名[:tag]
malulu@malulu:~/桌面$ docker pull mysql
Using default tag: latest # 如果不写tag(版本) 默认就是latest
latest: Pulling from library/mysql
f7ec5a41d630: Already exists # 分层下载 docker image的核心 联合文件系统
9444bb562699: Pull complete
6a4207b96940: Pull complete
181cefd361ce: Pull complete
8a2090759d8a: Pull complete
15f235e0d7ee: Pull complete
d870539cd9db: Pull complete
5726073179b6: Pull complete
eadfac8b2520: Pull complete
f5936a8c3f2b: Pull complete
cca8ee89e625: Pull complete
6c79df02586a: Pull complete
Digest: sha256:6e0014cdd88092545557dee5e9eb7e1a3c84c9a14ad2418d5f2231e930967a38 # 签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 真实地址
# 下面两条命令等价
docker pull mysql
docker pull docker.io/library/mysql:latest
# 指定版本下载 必须在仓库有这个版本
malulu@malulu:~/桌面$ docker pull mysql:5.7
5.7: Pulling from library/mysql
f7ec5a41d630: Already exists
9444bb562699: Already exists
6a4207b96940: Already exists
181cefd361ce: Already exists
8a2090759d8a: Already exists
15f235e0d7ee: Already exists
d870539cd9db: Already exists
7310c448ab4f: Pull complete
4a72aac2e800: Pull complete
b1ab932f17c4: Pull complete
1a985de740ee: Pull complete
Digest: sha256:e42a18d0bd0aa746a734a49cbbcc079ccdf6681c474a238d38e79dc0884e0ecc
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
删除镜像
# 删除指定的镜像
docker rmi -f 镜像ID
# 删除多个镜像
docker rmi -f 镜像ID 镜像ID 镜像ID 镜像ID
# 删除全部镜像
docker rmi -f $(docker images -aq)
说明:我们有了镜像才可以创建容器。
这里下载一个centos镜像来测试学习。
docker pull centos
docker run [可选参数] image
# 参数说明
--name="Name" # 容器名字 mysql01 mysql02 用来区分容器
-d # 后台方式运行
-it # 使用交互方式运行(需要提供一个控制台) 进入容器查看内容
-p # 指定容器的端口 -p 8080:8080
-p ip:主机端口:容器端口
-p 主机端口:容器端口 (常用)
-p 容器端口
容器端口
-P # 随机指定端口
# 测试
# 启动并进入容器
malulu@malulu:~/桌面$ docker run -it centos /bin/bash
[root@a8d9ce9627a4 /]# ls # 查看容器内的centos 基础镜像 很多命令都是不完善的
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr
# 从容器中退回主机
[root@a8d9ce9627a4 /]# exit
exit
malulu@malulu:~/桌面$
# 列出当前正在运行的容器
docker ps
# 可选项
-a # 列出当前正在运行的容器 + 历史运行过的容器
-n=? # 显示最近创建的n个容器
-q # 只显示容器的编号
exit # 直接停止容器并退出
ctrl+P+Q # 容器不停止退出
# 删除指定的容器 不能删除正在运行的容器 强制删除用rm -f
docker rm 容器ID
# 删除所有的容器
# 方式一 常用
docker rm -f $(docker ps -aq)
# 方式二
docker ps -a -q|xargs docker rm
docker start 容器ID # 启动容器
docker restart 容器ID # 重启容器
docker stop 容器ID # 停止当前正在运行的容器
docker kill 容器ID # 强制删除当前容器
# 后台启动容器
docker run -d 镜像名
# 比如 后台启动centos
docker run -d centos
# 问题 docker ps 时 发现 centos 停止了
# 常见的坑:docker容器使用后台运行,就必须要有一个前台进程,docker发现没有应用,就会自动停止
# 比如nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了
docker logs -f -t --tail number 容器ID
# 可选项
-tf # 显示日志
--tail number # 要显示日志条数
# 自己编写一段shell脚本
docker run -d centos /bin/sh -c "while true;do echo 666;sleep 1;done"
docker top 容器ID
docker inspect 容器ID
我们通常容器都是使用后台方式运行的,有时需要进入容器,修改一些配置
# 方式一
# 命令
docker exec -it 容器ID bashShell
# 测试
malulu@malulu:~/桌面$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9ff3b9c7ebd5 centos "/bin/sh -c 'while t…" 8 seconds ago Up 6 seconds lucid_wright
malulu@malulu:~/桌面$ docker exec -it 9ff3b9c7ebd5 /bin/bash
[root@9ff3b9c7ebd5 /]# ls
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr
[root@9ff3b9c7ebd5 /]#
# 方式二
docker attach 容器ID
# 测试
malulu@malulu:~/桌面$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9ff3b9c7ebd5 centos "/bin/sh -c 'while t…" 8 minutes ago Up 8 minutes lucid_wright
malulu@malulu:~/桌面$ docker attach 9ff3b9c7ebd5
666
666
666
666
666
666
# docker exec # 进入容器后开启一个新的终端 可以在里面操作(常用)
# docker attach # 进入容器正在执行的终端 不会启动新的终端
注意:是从容器内拷贝到主机。
docker cp 容器Id:容器内路径 目的的主机路径
只要容器存在就可以,跟容器是否运行没有关系。
拷贝是一个手动过程,后面我们使用 -V
数据卷的技术,可以实现自动同步。
attach Attach local standard input, output, and error streams to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container's filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes
第一步:搜索镜像,建议去DockerHub搜索,可以看到帮助文档
https://registry.hub.docker.com/search?q=nginx&type=image
第二步:拉取镜像
malulu@malulu:~/桌面$ docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
f7ec5a41d630: Already exists
aa1efa14b3bf: Pull complete
b78b95af9b17: Pull complete
c7d6bca2b8dc: Pull complete
cf16cd8e71e0: Pull complete
0241c68333ef: Pull complete
Digest: sha256:75a55d33ecc73c2a242450a9f1cc858499d468f077ea942867e662c247b5e412
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
malulu@malulu:~/桌面$
第三步:运行测试
# -d 后台运行
# --name 给容器命名
# -p 宿主机端口:容器内部端口
malulu@malulu:~/桌面$ docker run -d --name nginx01 -p 3344:80 nginx
699b9cecd0a07f8db6e888722a2dada1c9b9be6d77efc7996c4b6758dd72f587
malulu@malulu:~/桌面$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
699b9cecd0a0 nginx "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:3344->80/tcp nginx01
malulu@malulu:~/桌面$ curl localhost:3344
# 进入容器
malulu@malulu:~/桌面$ docker exec -it nginx01 /bin/bash
root@699b9cecd0a0:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@699b9cecd0a0:/# cd /etc/nginx/
root@699b9cecd0a0:/etc/nginx# ls
conf.d fastcgi_params koi-utf koi-win mime.types modules nginx.conf scgi_params uwsgi_params win-utf
root@699b9cecd0a0:/etc/nginx# exit
第四步:公网访问
# es 暴露的端口很多
# es 十分的耗内存
# es 数据一般需要放置到安全目录 挂载
docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:tag
# --net somenetwork 网络配置
# 启动 Elasticsearch
docker run -d --name elasticsearch01 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.12.0
# 启动之后,服务器会特别卡
# 所以需要增加内存的限制
# 修改配置文件 -e 环境配置修改
docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.12.0
# 查看CPU使用情况
docker stats 容器ID
# 测试es是否安装成功
curl localhost:9200
Docker图形化界面管理工具,提供一个后台面板供我们操作。
访问测试:
http://192.168.2.143:8088
http://localhost:8088
为用户 admin 设置密码 admin123456
登录成功后,选择本地Docker环境
进入之后的面板
可视化面板我们平时不会使用,用来测试玩玩。
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行所需库、环境变量和配置文件。
所有的应用,直接打包docker镜像,就可以直接跑起来。
如何获取到镜像:
UnionFS(联合文件系统)
我们下载的时候看到的一层层就是这个!
Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改
作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
Docker镜像加载原理
Docker的镜像实际上由一层层的文件系统组成,这种层级的文件系统叫做UnionFS。
系统启动需要引导加载。
bootfs(boot file system)主要包含bootloader(加载器)和kernel(内核),bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs(root file system),在bootfs之上,包含的就是典型Linux系统中的 /dev,/proc,/bin,/etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu, Centos等等。容器就是一个小的虚拟机环境。
平时我们在虚拟机中安装CentOs都是好几个G,为什么在Docker里面才200多M?
对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。
所以说,虚拟机是分钟级别,容器是秒级别。是因为启动虚拟机需要启动内核引导,非常慢,而容器底层还是使用主机的内核。
分层的镜像
我们可以去下载一个镜像,注意观察下载的日志输出,可以看到的是一层一层的在下载。
**思考:**为什么Docker镜像要采用这种分层的结构呢?
最大的好处,我觉得莫过于是资源共享了。比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份Base镜像,同时内存中也只需要加载一份Base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。
查看镜像分层的方式可以通过 docker image inspect 命令。
docker image inspect redis:latest
理解:
所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于Ubuntu Linux 16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。
这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。
Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
Linux上可用的存储引擎有AUFS、Overlay2、Device Mapper、Btrfs 以及ZFS。顾名思义,每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。
Docker在Windows上仅支持windowsfilter一种存储引擎。
下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。
特点
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层就是我们通常说的容器层,容器之下的都叫镜像层。
如何提交一个自己的镜像呢?
docker commit 提交容器成为一个新的镜像
docker commit -m="提交的描述信息" -a="作者" 容器Id 目标镜像名:[TAG]
实战测试:
# 1.启动一个默认的tomcat
# 2.发现这个默认的tomcat是没有webapps应用,是因为官方镜像默认webapps下面是没有文件的
# 3.自己拷贝进去了基本的文件
# 4.将我们操作过的容器通过commit提交为一个镜像。我们以后就使用我们修改过的镜像即可。
总结:
如果你想要保存当前容器的状态 ,就可以通过commit来提交,获得一个镜像。就好比虚拟机的快照。
将应用和环境打包成一个镜像!
数据?如果数据都在容器中,那么我们容器删除,数据就会丢失!需求:数据可以持久化
MySQL,容器删了,相当于删库跑路!需求:MySQL数据可以存储到本地
容器之间可以有一个数据共享的技术!Docker容器中产生的数据,同步到本地!
这就是卷技术!相当于目录的挂载,将我们容器内的目录,挂载到Linux上面!
**总结:**为什么使用容器卷?为了容器的持久化和同步操作,容器间也是可以数据共享的(即多个容器使用同一个本地目录)
方式一:直接使用命令来挂载 -v
docker run -v 主机内目录:容器内目录
通过命令 docker inspect
来查看挂载信息,如下:
"Mounts": [
{
"Type": "bind",
"Source": "/home/ceshi", # 主机内地址
"Destination": "/home", # docker容器内地址
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
测试文件的同步:
思考:MySQL的数据持久化问题。
# 获取镜像
docker pull mysql:5.7
# 运行容器 需要做数据挂载
# 注意: 安装启动mysql时 需要配置密码的
# 官方测试(DockerHub) docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
# 启动
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=Malulu@960610 --name mysql01 mysql:5.7
# 启动成功后 在使用Navicat来测试
# Navicat连接到Ubuntu的3310 3310和容器内的3306映射 此时我们就可以连接上了
假设我们将容器删除,我们挂载到本地的数据卷依旧没有丢失,这就实现了容器数据持久化的功能。
# 查看所有卷的信息
docker volume ls
# 匿名挂载
-v 容器内目录
docker run -d -P --name nginx -v /etc/nginx nginx
# 这样就属于匿名挂载 在 -v 后只写了容器内目录 没有写主机的目录
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
通过 -v 卷名:容器内目录
的格式属于具名挂载。
使用命令 docker volume inspect 卷名
来查看这个这个卷的信息。
所有的Docker容器内的卷,在没有指定目录的情况下都是在主机的 /var/lib/docker/volumes/xxx/_data
目录下。
我们通过具名挂载可以方便的找到我们的一个卷,大多数情况下使用具名挂载。
如何确定是具名挂载还是匿名挂载还是指定路径挂载?
-v 容器内路径 # 匿名挂载
-v 卷名:容器内路径 # 具名挂载
-v /宿主机路径:容器内路径 # 指定路径挂载
扩展:
# 通过 -v 容器内路径:ro rw 改变读写权限
ro readonly # 只读
rw readwrite # 可读可写
# 一旦设置了这个权限 容器对我们挂载出来的内容就有限定了
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
# ro 只要看到ro就说明这个路径只能通过宿主机来操作 容器内部是无法操作的
DockerFile就是用来构建Docker镜像的构建文件,这个文件其实就是一个命令脚本。
通过这个脚本可以生成镜像,镜像是一层一层的,脚本是一个一个的命令,每个命令都是一层。
# 创建一个dockerfile文件 名字可以随机 建议Dockerfile
# 文件中的内容
# 指令(大写) 参数
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "-----end-----"
CMD /bin/bash
# 这里的每个命令镜像的一层
通过 docker build
来创建自己的命令。
docker build -f ./dockerfile1 -t malulu-centos:1.0 .
启动自己创建的镜像
这两个卷在外部一定有同步的目录。
查看一下卷挂载的路径。
然后测试一下刚才创建的两个文件是否同步到宿主机。
这种方式我们以后用的非常多,因为我们通常会构建自己的镜像。假设构建镜像时没有挂载卷,就需要手动挂载(具名挂载)。