初始docker
前置知识
通过面向对象的知识来了解docker中的镜像和容器就很好理解了,docker是C/S架构
-
镜像:是一个只读的模板,可以用来创建容器。类
-
容器:是docker的运行实例,提供了一个独立的可移植的环境,可以在这个环境中运行应用程序。实例,1个或多个
-
docker仓库:用来存储docker镜像的地方,最常用的就是DockerHub
-
docker daemon: 服务端的守护进程,负责管理服务器的各种资源。
-
docker client负责向docker daemon发送请求, docker daemon收到请求后进行处理,然后将结果返回给docker client。
windows不需要第三方工具连接SSH
# 打开cmd 运行 mstsc 跟着步骤操作
mstsc
# 打开cmd 运行 SSH root@服务器地址 然后输入密码即可
SSH root@1.2.3.4
简单命令
sudo su 切换到超级管理员
exit 切换到普通用户
cd 回家 root用户回根目录 普通用户回到带有名字的目录
mkdir -p /demo/html
mkdir -p是一个Linux命令,用于创建目录。其中,-p选项表示如果父级目录不存在,则会自动创建父级目录。
安装docker
yum update # 更新yum仓库
# 6 安装
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install docker-ce -y
修改镜像地址
https://cr.console.aliyun.com/cn-shanghai/instances/mirrors
vi /etc/docker/daemon.json
# 保存并重启docker
systemctl daemon-reload # 重新加载docker配置
systemctl restart docker # 重启docker
查看安装的版本
docker -v
docker --version
启动和停止
# 启动 docker
sudo systemctl start docker
# 停止 docker
sudo systemctl stop docker
# 设置开机启动
sudo systemctl enable docker
# 重启 docker
sudo systemctl restart docker
# 重新加载 docker 配置
sudo systemctl daemon-reload
# 查看 docker 内容器的运行状态
sudo docker stats
# 查看 docker 概要信息
sudo docker info
# 查看 docker 帮助文档
sudo docker --help
查看全部镜像
docker images
docker image ls
run 把镜像运行成容器
运行
[sudo] docker run -id --name=centos7 centos:centos7 # 如果不写版本 默认就是latest
# id 启动容器 不进入容器内部
# it 启动容器 进入容器内部
# --name 起一个别名 别名必须唯一
# centos:centos7 基于哪一个镜像去运行
# -i 如果不需要进入容器内部进行交互式输入命令 那么 -i是可以省略的
运行的后面也可以跟命令
sudo docker run -it --name=t1 centos:centos7 sleep 10 # 10秒结束
查看正则运行的容器
[sudo] docker ps
[sudo] docker ps -s
查看全部容器
[sudo] docker ps -a
执行命令 返回命令结果
# 命令
[sudo] docker exec -it <container> bash
ccsvip@ccsvip-virtual-machine:~$ sudo docker ps -s
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES SIZE
3c889a59ed12 centos:centos7 "/bin/bash" 6 minutes ago Up 6 minutes nervous_maxwell 0B (virtual 204MB)
ccsvip@ccsvip-virtual-machine:~$ sudo docker exec -it 3c889a59ed12 bash
# 可以简写使用部分id 后面也可以跟上要执行的命令
[sudo] docker exec -it 3c88 ls
/bin/bash和sh命令
如果 sudo docker exec -it id号 /bin/bash进不去 就试试 sudo docker exec -it id号 sh
启动已经创建过但是停止了的容器
[sudo] docker start id号或id号简称 如果是id号 写前3位就可以了
停止运行的容器
[sudo] docker stop id或容器名称
删除容器 rm
[sudo] docker rm name1 name2 # 删多个 类似pip
[sudo] docker rm name # 删单个
name可以是容器的名称 也可以是 id的名称
停止全部容器
[sudo] docker stop `sudo docker ps -a -q`
[sudo] docker stop $(sudo docker ps -sq)
删除非运行状态的容器
[sudo] docker rm `docker ps -f status=exited`
[sudo] docker rm $(docker ps -f status=exited)
删除全部容器
[sudo] docker rm `docker -ps -a -q`
[sudo] docker rm $(docker -ps -aq)
# 注 -f 强制删除 慎用
删除全部镜像
[sudo] docker rmi `docker images -q`
[sudo] docker rmi $(docker images -q)
查看日志
docker logs id名或容器名 # 查看全部日志
docker logs -f id名或容器名 # 持续查看最新日志
docker logs -n 数字 # 查看最近n条日志
-v命令 跟宿主机的文件做映射
您可以将主机上的目录或文件与容器中的目录或文件进行关联,使得容器可以访问和修改主机上的数据。
# 语法
sudo docker run -it --name=centos7 -v 主机目录或文件的路径:容器的文件或目录 centos:centos7
sudo docker run -it --name=centos7 -v /home/小满:/小满 centos:centos7
# 注意点 容器的目录 也就是容器:路径 如果目录不存在 会自动去创建的。
匿名挂载
docker run -id --name nginx2 -v /usr/share/nginx/html/ -p 80:80 nginx # 注意 如果只写一个路径 表示容器的路径
# 所有的挂载都会到 var/lib/docker/volumes/ 这个目录
root@iZbp1hwoc9gqiqk631pnpfZ:/# ls var/lib/docker/volumes/
293a9827a459f39a380748bae08ababd1ae141e5c745ed155dd3da7bc3ca8880 c4ff0ff27f65ba79917def3f11f6725945b98f223c3a3f880f8faafb529b2fca
3e58f4a97113dd43538c0d30f0ba58ee9a8e45a755dce1e7ca3b401f58c286a3 c5ad942882fe21f4212bb8523205d0fde58c616088ae794b213df021acc56b30
79fa4e6cc3ae3bfafa38d2e0400c5b1785a3d4966bc62806cd00d2589793201b ef8bc9828f671d4e5d394cd55d064db37125ad4caa4c9b8882a6b89451280acb
backingFsBlockDev metadata.db
# 通过 docker inspect id或者名称能查询到挂载信息
"Mounts": [
{
"Type": "bind",
"Source": "/data",
"Destination": "/abc/123",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
挂载权限 :ro只读 :rw读写
sudo docker run -it --name=centos7 -v /home/小满:/小满:ro centos:centos7 # 只读模式 容器内部只能查看无法操作
sudo docker run -it --name=centos7 -v /home/小满:/小满:rw centos:centos7 # 读写模式 容器内部可以修改新增
继承 --volumes-from
#容器 centos7-01 指定目录挂载
docker run -di -v /mydata/docker_centos/data:/usr/local/data --name centos7-01 centos:7
#容器 centos7-04 和 centos7-05 相当于继承 centos7-01 容器的挂载目录
docker run -di --volumes-fn centos7-01--name centos7-04 centos:7docker run -di --volumes-fm centos7-01 --name centos7-05 centos :7
查看目录卷的挂载关系
端口映射
运行一个MySQL容器做端口映射,需要安装 net-tools
根据搜索结果,你的命令是在 Docker 中运行一个 MySQL 5.7 容器,并将容器的 3306 端口映射到主机的 3308 端口。命令如下所示:
[sudo] docker run -id --name=mysql5.7 -p 3308:3306 -e MYSQL_ROOT_PASSWORD=xm123 mysql:5.7
这个命令的含义是:
sudo docker run
:运行一个 Docker 容器。-id
:以交互模式和后台运行的方式启动容器。--name=mysql5.7
:给容器指定一个名称为 "mysql5.7"。-p 3308:3306
:将容器的 3306 端口映射到主机的 3308 端口。-e MYSQL_ROOT_PASSWORD=xm123
:设置 MySQL 的 root 用户密码为 "xm123"。mysql:5.7
:使用 MySQL 5.7 镜像创建容器。
这个命令的目的是在 Docker 中创建一个 MySQL 5.7 容器,并通过端口映射使其可以通过主机的 3308 端口访问。容器的名称为 "mysql5.7",MySQL 的 root 用户密码设置为 "xm123"。
注意:宿主连接的地址应该为:mysql -h ipaddr得到的地址 -P 3308 -uroot -p
随机端口映射 -P
[sudo] docker run -d -P imagesname
[sudo] docker ps 可以查看端口
映射多个端口
[sudo] docker run -d -p 8000:5000 -p 8001:5000 image-name
-e 设置环境变量
docker run -d --name mysql -v ./mysqldata:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=xm123 -p 3308:3306 mysql:5.7
重启重启策略 一般是设置 always
docker run --name nginx-test -d -P --restart always nginx # 这样设置 --restart always 就可以自动重启了
# 上面这种情况,如果是运行在虚拟机,虚拟机重启可以模拟
# 如果运行在服务器,使用systemctl restart docker 重启docker 可以模拟。
net-tools
# 安装
sudo apt install net-tools
yum install net-tools
# 查看端口使用情况
sudo netstat -nlp | grep 3308 # 端口号
netstat -nlp | grep 3308
如果docker停止了,那么服务就连不上了
# docker
ccsvip@ccsvip-virtual-machine:/home$ sudo docker stop mysql5.7
mysql5.7
# 宿主机
C:\Users\chuxu>mysql -h 192.168.147.128 -P 3308 -uroot -p
Enter password: *****
ERROR 2003 (HY000): Can't connect to MySQL server on '地址:3308' (10061)
ubuntu、debian 更新以及安装
mysql容器的底层操作系统是debian。debian系和ubuntu属于统一分支
[sudo] apt-get update # 更新
[sudo] apt install xxx # 安装
[sudo] apt install vim -y # -y 无需手动确认
文件拷贝 在宿主机执行 cp
顺序说明: 冒号右边是目标地址 冒号左边是原始地址
docker cp <宿主机文件路径> <容器名称或ID>:<容器目标路径>
[sudo] docker cp ./1.txt python:/ # 把宿主机的1.txt 拷贝到容器的根目录
docker cp <容器名称或ID>:<容器文件路径> <宿主机目标路径>
[sudo] docker cp python:/cancer ./ # 将容器根目录下的 cancer文件夹(含内部文件)拷贝到宿主机的当前文件夹
镜像不含前台进程,进入操作 --rm
docker run -ti -rm book bash
docker run:运行一个新的Docker容器。
-ti:使用交互式终端和终端的伪终端。
--rm:容器退出后自动删除容器。这可以确保容器在退出后不会占用磁盘空间。
book:指定要使用的镜像。
bash:在容器中运行的命令,这里是一个交互式的bash终端。
容器其他操作
镜像详细信息
docker image inspect mysql:5.7
查看容器内进程
docker top 容器名称或id
root@iZbp1hwoc9gqiqk631pnpfZ:~/project# docker top mysql
查看容器的ip地址
[sudo] docker inspect 容器名称或id
# 返回的结果是一个json格式的内容
获取ip地址 容器一定要是开启状态!
ccsvip@ccsvip-virtual-machine:/home$ sudo docker inspect mysql5.7 --format="{{.NetworkSettings.IPAddress}}"
172.17.0.2
容器之间互相ping
apt-get update
apt-get install iputils-ping
ping 地址
数据卷相关操作
设置数据卷
查看容器具体信息,就可以知道挂载到哪一个目录了
docker inspect nginx-test
# 执行后 找到 Mounts
"Mounts": [
{
"Type": "volume", # 类型数据卷
"Name": "nginx-html", # 名称
"Source": "/var/lib/docker/volumes/nginx-html/_data", # 宿主机目录
"Destination": "/usr/share/nginx/html", # 容器内的目录
"Driver": "local",
"Mode": "z",
"RW": true, # 可读可写
"Propagation": ""
}
],
查看全部数据卷 docker volume ls
查看某个数据卷的详细信息 docker volume inspect 容器名称或id
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker volume inspect nginx-test
[
{
"CreatedAt": "2024-06-26T14:22:18+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/nginx-test/_data",
"Name": "nginx-test",
"Options": null,
"Scope": "local"
}
]
创建数据卷 docker volume create 数据卷名称
默认会创建在/var/lib/docker/volumes/volume_test/_data"这个目录。
这样不论在宿主机容器内,修改内容都是会同步的,后续即便删除了容器内容也是还在的。
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker volume create volume_test
volume_test
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker volume inspect volume_test
[
{
"CreatedAt": "2024-06-26T14:33:14+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/volume_test/_data",
"Name": "volume_test",
"Options": null,
"Scope": "local"
}
]
删除数据卷 docker volume rm 数据卷名称或id
注意,正在运行的容器挂载的数据卷无法直接删除,可以删除容器后再删除数据卷。
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker volume rm volume_test
volume_test
应用部署
mysql部署
/var/lib/mysql -e MYSQL_ROOT_PASSWORD=
/var/lib/mysql 备份路径
MYSQL_ROOT_PASSWORD 设置root密码
#0 dokcer 中部署mysql,以后不需要在宿主机上装mysql
#1 没有做目录映射---》配置文件--》表数据都在容器中---》一旦删除--》所有都没了
docker run -di --name=mysql -p 3308:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
# 2 做目录(配置文件和数据文件)和端口映射
# 做目录映射:data文件,配置文件
# 创建文件夹
mkdir /mysql
mkdir /mysql/conf.d
mkdir /mysql/data/
vi /mysql/my.cnf
[client]
default-character-set=utf8
[mysqld]
user=mysql
character-set-server=utf8
default_authentication_plugin=mysql_native_password
secure_file_priv=/var/lib/mysql
expire_logs_days=7
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
max_connections=1000
docker run -di -v /mysql/data/:/var/lib/mysql -v /mysql/conf.d:/etc/mysql/conf.d -v /mysql/my.cnf:/etc/mysql/my.cnf -p 3306:3306 --name mysql5.7 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
# 创建库,创建表,插入数据
# 关闭容器,删除容器,myslq的容器没了,但是数据在宿主机上放着
docker stop mysql2
docker rm mysql2
##docker rm mysql -f 容器之间删了
# 再运行起一个容器,做好目录映射,数据都回来了
docker run -di -v /mysql/data/:/var/lib/mysql -v /mysql/conf.d:/etc/mysql/conf.d -v /mysql/my.cnf:/etc/mysql/my.cnf -p 3307:3306 --name mysql2 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
# 补充 -e参数--》环境变量
-不同镜像提供不同参数
-传入后放入环境变量
echo $MYSQL_ROOT_PASSWORD
这些文件是用于组织和存储容器内部的文件和目录的。以下是对这些文件的简要说明:
bin
:包含可执行文件(二进制文件)的目录,用于存放一些基本的系统命令和工具。boot
:包含启动相关的文件,如内核和引导加载程序。dev
:包含设备文件,用于与主机系统进行交互。docker-entrypoint-initdb.d
:如果你的容器是MySQL,这个目录用于存放初始化数据库的脚本。entrypoint.sh
:如果你的容器有自定义的入口脚本,它可能会存放在这个文件中。etc
:包含系统配置文件的目录,如网络配置、软件配置等。home
:用户的主目录,用于存放用户的个人文件和配置。lib
:包含共享库文件的目录,这些库文件被可执行文件使用。lib64
:类似于lib
目录,但用于64位系统。media
:用于挂载可移动介质(如CD、DVD、USB驱动器)的目录。mnt
:用于挂载其他文件系统的目录。opt
:用于存放可选软件包的目录。proc
:虚拟文件系统,提供有关系统进程的信息。root
:root用户的主目录。run
:用于存放运行时文件的目录,如PID文件和锁文件。sbin
:包含系统管理员使用的系统命令和工具。srv
:用于存放服务相关的数据和文件。sys
:虚拟文件系统,提供有关系统硬件和内核的信息。tmp
:用于存放临时文件的目录。usr
:包含用户安装的应用程序和文件的目录。var
:包含可变数据的目录,如日志文件、数据库文件等。
如果你想将宿主机的文件与容器共享,你可以使用-v
选项将宿主机的目录挂载到容器的相应目录中。例如,你可以将宿主机的MySQL数据目录挂载到容器的/var/lib/mysql
目录,将配置文件挂载到/etc/mysql/conf.d
目录。
redis部署
#1 拉取redis镜像
docker pull redis #最新
mkdir /root/data
vim /root/redis.conf
bind 0.0.0.0
daemonize NO
protected-mode yes
requirepass 123456
bind 0.0.0.0:这句代码指定Redis监听所有可用的网络接口,允许从任意IP地址访问Redis服务器。
daemonize NO:这句代码指定Redis以非守护进程的方式运行,即在前台运行而不是作为后台进程。
protected-mode yes:这句代码启用Redis的保护模式,该模式会限制对Redis的远程访问,只允许本地访问。
requirepass xm123:这句代码设置Redis的访问密码为"xm123",需要在连接Redis时提供正确的密码才能进行操作
# 运行
#启动容器时,运行的命令是什么 redis-server /etc/redis/redis.conf
docker run -id -p 6379:6379 --name redis -v /root/redis.conf:/etc/redis/redis.conf -v /root/data:/data redis redis-server /etc/redis/redis.conf
# 在容器运行时,可以自己定制运行命名 举例:docker run -id centos:centos7 ls
# 远程链接redis操作
nginx部署
/etc/nginx/
:NGINX的配置文件通常位于此目录中。/usr/share/nginx/
:NGINX的静态资源文件(如HTML、CSS、JavaScript文件)通常位于此目录中。/var/log/nginx/
:NGINX的日志文件通常位于此目录中。
# 拉取nginx镜像
docker pull nginx
# run起容器
# docker run -id --name nginx -p 80:80 nginx
# /usr/share/nginx/html
docker run -id --name nginx1 -p 8008:80 -v /root/html:/usr/share/nginx/html nginx
# 以后只需要修改宿主机的/root/html 路径,看到页面就是修改后的
docker网络
创建网络后可以直接通过网络名称取
创建网络 docker network create 网络名
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker network create blog_network
8ed8ce47e1d39c84f05d2614ddaeb86b69e2453d4520ca4076d456121af9f584
列出所有网络 docker network ls
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker network ls
NETWORK ID NAME DRIVER SCOPE
dbaa99745700 1panel-network bridge local
8ed8ce47e1d3 blog_network bridge local
4c2ef89812cb bridge bridge local
068181900e56 docker-compose-luffy_web bridge local
3058fcd56838 host host local
796d81083b6b none null local
d39ef21c7b10 project_default bridge local
将容器加入网络docker network connect 网络名称 容器名称
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker network connect blog_network nginx-html
root@iZbp1hwoc9gqiqk631pnpfZ:~#
查看网络 docker network inspect 网络名称或网络id
Containers中的 Name 就是加入到该网络的容器。
加入网络后容器之间可以互相ping 也可以run的时候直接写容器名称
删除网络 docker network rm 网络名称或网络id
docker network rm test_network
将容器保存为对象
查看镜像
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos centos7 eeb6ee3f44bd 2 years ago 204MB
启动容器,并写入一些内容
docker run -id --name centos centos:centos7
docker exec -it centos /bin/bash
yum update -f
yum install vim
vim cancer.txt
写入一些内容在里面
exit 退出
制作成镜像
docker commit centos centos_with_vim
# 解释 docker commit 容器名称 打包后的镜像名称:[tag 可选]
docker commit -a "cancer" -m "centos7+tomcat" mycentos mycentos:7
docker commit
:这是Docker命令,用于创建一个新的镜像。-a "cancer"
:这是docker commit
命令的选项之一,用于指定作者的信息。在这个例子中,作者被设置为"cancer"。-m "centos7+tomcat"
:这是docker commit
命令的选项之一,用于指定提交的消息。在这个例子中,提交消息被设置为"centos7+tomcat"。mycentos
:这是要创建镜像的容器的名称或ID。在这个例子中,容器名称为"mycentos"。mycentos:7
:这是新镜像的名称和标签。在这个例子中,新镜像被命名为"mycentos",并带有标签"7"。
再次启动容器 查看内容
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker run -it --name centos centos_vim
[root@6c4dea98675f /]# ls
anaconda-post.log bin cancer.txt dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
[root@6c4dea98675f /]# cat cancer.txt
xm is beautiful
i think this is a good girl!!
本地镜像推送给到docker hub
执行命令docker tag id名字或者镜像名字 然后是下面红框的名字:[可选标签]
执行命令 docker pull xxx
这里的xxx就是
docker pull cancerwake/docker_vim:v1
镜像备份和恢复
- i input
- o output
备份
docker save -o 结果 镜像名称
# 例如
docker save -o centos_vim.tar centos_demo
恢复
docker load -i 镜像名称
# 例如
docker load -i centos_vim.tar
dockerfile
注:执行run后面跟的命令优先级是高于内部cmd命令的
注:CMD和ENTRYPOINT指令是容器运行时候生效,其他指令都是容器构建时候生效。
概念
Dockerfile是一个文本文件,里面包含了一条条的指令,用老告诉docker如何来构建镜像,这个镜像中包括了我们应用程序执行的所有命令,各种依赖,配置环境,和应用程序所需要的所有内容,一般来说包括下面这些内容:
- 精简版的操作系统,比如Alpine
- 应用程序运行时的环境,比如NodeJS python java
- 应用程序,比如django 或者SpritBoot打包好的jar包
- 应用程序的第三方依赖库或者包
- 应用程序的配置文件、环境变量等。
一般来说,我们会在项目根目录下创建一个Dockerfile文件,在这个文件中写入构建镜像,所需要的各种指令之后,docker就会根据这个Dockerfile文件来构建一个镜像,有了这个镜像之后就可以使用这个镜像来创建容器,然后在容器中运行应用程序。
# 1 基础镜像
# 我们需要先指定一个基础镜像
# 镜像是按层次结构来构建的,每一层都是基于上一层的。
# 所以我们需要先指定一个基础镜像,在这个基础镜像上添加我们的应用程序。
# 2 配置完镜像后,还需要把应用程序复制镜像中, --> copy 源路径 目标路径
# 源路径:相对于Dockerfile文件的路径
# 目标路径:目标路径是相对于镜像的路径
# 3 在镜像中运行程序 可以使用CMD命令
# 注意引号是双引号 CMD ["node", "index.js"] 方括号第一个参数代表可执行程序的名字 后面的代表参数
# 也可以写成CMD node /index.js
# 4 构建镜像
# 方式1: docker build -t="name" .
# 方式2: docker build -t name .
# 案例中 docker build -t hello-docker .
FROM ubuntu:latest # FROM 基础镜像 基于哪一个镜像去构建
LABEL maintainer="your-name@example.com" # LEBAL 声明元数据标签
LABEL version="1.0"
LABEL description="This is a sample Docker image."
WORKDIR /app # 工作目录 如果没有会创建出来 相当于 mkdir 然后cd进去 后面的RUN命令都是在定义的这个目录下去执行
RUN apt-get update && apt-get install -y \ # 命令 后面跟上Linux命令 是dockerfile的核心
python3 \
python3-pip
COPY requirements.txt . # 将宿主机的文件 复制到镜像内
RUN pip3 install -r requirements.txt
COPY . .
CMD ["python3", "app.py"] # 执行CMD命令
CMD 和 ENTRYPOINT的区别
https://www.cnblogs.com/littlecc/p/17419047.html
run后面的命令是可以覆盖CMD命令的
# 正常的输出
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker run hello:1.0
hello world
# 覆盖CMD命令
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker run hello:1.0 echo "hello xm"
hello xm
--no-cache
构建一个没有缓存的镜像
使用场景,比如你在Dockerfile里面写了一个 RUN git clone xxx 这样就需要加上 --no-cache
docker build -t book . -f Dockerfile --no-cache
CMD两种方式的区别 [] 这种不会解析环境变量
下面这种则能解析环境变量 值得一提的是 ,环境变量 设置加不加引号都是可以的。
ROM centos:centos7
ENV CONTENT=海月 # 这样也是可以的
CMD echo $CONTENT
因为能使用环境变量 所以run的时候能动态修改值
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker run -e CONTENT=大乔 hello:5.0
大乔
WORKDIR 注意 相当于mkdir 然后cd 进入
根据搜索结果,Dockerfile中的WORKDIR
指令用于设置工作目录。每个WORKDIR
指令都会更改容器中的当前工作目录。在你提供的Dockerfile中,有三个连续的WORKDIR
指令:
WORKDIR /a
WORKDIR b
WORKDIR c
这意味着容器的当前工作目录将被设置为/a
,然后在此基础上创建一个名为b
的子目录,最后在b
目录中创建一个名为c
的子目录。因此,当你运行容器并执行pwd
命令时,输出将是/a/b/c
。
如果WORKDIR执行时父目录不存在也会自动创建
root@iZbp1hwoc9gqiqk631pnpfZ:~# cat helloworld
FROM centos:centos7
WORKDIR /a/b/c/d/e
CMD pwd
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker run test:1.0
/a/b/c/d/e
WORKDIR引用环境变量
RUN 命令
思考:为什么运行的时候修改环境变量的值结果没有发生变化
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker run -e NAME=阿珂 test:9.0
小满最棒啦
# 因为运行时机问题
# 在运行容器时使用-e选项来设置环境变量时,它会覆盖Dockerfile中设置的默认值。因此,即使在运行容器时设置了NAME=阿珂,但在Dockerfile中设置的默认值小满最棒啦仍然会被使用。
ADD
需求如下:
代码实现
# 代码地址
https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.25/bin/apache-tomcat-10.1.25.tar.gz
FROM nginx
WORKDIR /app
COPY dist.tar.gz .
RUN tar -xvzf dist.tar.gz
RUN cp -r dist/* /usr/share/nginx/html
ENTRYPOINT ["nginx", "-g", "daemon off;"] # 别忘记分号
# 注意 cp -r的时候 复制的是文件夹内的内容 不会复制当前文件夹
ENTRYPONIT
关于 . 的理解
dockerfile案例-1
构建一个容器 一运行就打印helloworld
# 1. 创建一个文件 其实就是Dockerfile
vim hellworld
# helloworld内容
FROM centos:centos7
CMD ["echo", "hello world"]
# 构建 在当前目录下查找helloworld Dockerfile 去构建名称为helloworld的镜像
# -t 可以指定镜像名称和标签
docker build -t helloworld . -f helloworld
# 运行镜像
docker run helloworld
dockerfile案例0
// index.js内容
console.log("你好,我是小满,我正在学习docker!")
// Dockerfile内容
FROM node:14-alpine
COPY index.js /index.js
CMD ["node", "index.js"]
// docker build -t hello-docker .
// docker run hello-docker
dockerfile案例1
1 在宿主机新建一个Dockerfile 写一些内容
Dockerfile 没有后缀 只能交这个名字
FROM centos
ENV name 小满
ENV age 3
RUN mkdir data
RUN echo "print(True)" > /data/result.py
RUN echo $name
RUN echo $age
WORKDIR data
2 宿主机构建
docker build -t="镜像的名字" . # 别忘记 . 它的意思就是在当前目录下找。
3 构建成功后 进入容器查看结果
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker build -t="demo" .
0.0s
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo latest 43eefa559286 14 seconds ago 917MB
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker run -id --name demo1 demo
85831a56a21939558f35349272d9b62c80718153e89e5f11163e1c5828e7932e
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker exec -it demo1 /bin/bash
root@85831a56a219:/data# ls
result.py
root@85831a56a219:/data# python result.py
True
dockerfile案例2
1 在宿主机新建一个Dockerfile
FROM python
ENV name 小满
ENV age 3
RUN mkdir /data
RUN echo "input()" > /data/result.py
RUN echo $name
RUN echo $age
WORKDIR /data
CMD ['python', './result.py'] # 运行容器时会默认加上 /bin/sh -c
2 宿主机构建
docker build -t="demo" .
3 构建成功后 进入容器查看结果
# 错误示范
docker run -id --name demo demo
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker logs demo
/bin/sh: 1: [python,: not found
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cb525bf6f078 demo "/bin/sh -c '['pytho…" About a minute ago Exited (127) About a minute ago demo
# 注意 COMMAND 部分
# 优化后的示范
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker run -id --name demo demo python /data/result.py
root@c898485f5a7f:/data# ls
result.py
root@c898485f5a7f:/data# python
Python 3.10.1 (main, Dec 21 2021, 09:01:08) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.getenv("age")
'3'
>>> exit()
root@c898485f5a7f:/data# exit
exit
root@iZbp1hwoc9gqiqk631pnpfZ:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c898485f5a7f demo "python /data/result…" About a minute ago Up About a minute demo
# COMMAND 部分已被修改了
Dockerfile 上线django项目(前后端结合)
# Dockerfile内容如下
FROM python
WORKDIR /book
COPY . .
RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
CMD ["python", "manage.py", "runserver", "0.0.0.0:8888"]
# 制作镜像命令如下
docker build -t django_demo . -f Dockerfile
# 启动命令如下
docker run -d -p 8888:8888 -v /root/django_test/:/book django_demo
# 上线的时候发现post请求没有注释掉csrf中间件,于是在宿主机中解决,容器内自动修改。
逻辑卷
docker容器有一个特点,容器中的数据是不会持久化的,当我们创建一个容器的时候,通常以一个干净的文件系统开始。容器启动之后我们可以在容器中创建文件,修改文件,但是容器停止之后,容器中的所有数据都会丢失掉,如果我们想要持久化容器中的数据应该怎么做呢?逻辑卷就是用来解决这个问题的。它可以把容器中的目录或者指定路径映射到宿主机的某个目录或者位置上,这样就可以将数据保存到宿主机的磁盘上,实现了数据的持久化。
实际上我们的容器就好像是一个简易版的操作系统,只不过系统中只安装了我们的程序运行所需要的环境,前边说到我们的容器是可以删除的,那如果删除了,容器中的程序产生的需要持久化的数据怎么办呢?容器运行的时候我们可以进容器去查看,容器一旦删除就什么都没有了。
所以数据卷就是来解决这个问题的,是用来将数据持久化到我们宿主机上,与容器间实现数据共字,简单的说就是将宿主机的目录映射到容器中的目录,应用程序在容器中的目录读写数据会同步到宿主机上,这样容器产生的数据就可以持久化了,比如我们的数据库容器,就可以把数据存储到我们宿主机上的真实磁盘中。
镜像分层
每一个Dockerfile命令都会构建一层镜像(本质上是每一层都会启动一个容器,执行完命令后,将容器进行提交,通过查看下载下来的镜像,发现历史层信息的层ID是missing,其实是因为原本的层id只存在于构建镜像的宿主机上,一旦转移镜像后,历史层消息中将只保留最新一层的ID
# 只要执行一个命令就会多一层
RUN yum install vim -y
RUN yum install git -y
# 查看镜像分层的命令
docker history liuqingzheng/lqz_books:v1
# 好处:
构建快,分发方便,如果本地有某一层了,这一层就不需要下载了
# 补充:Dcokerfile写命令,建议多条命令合为一条---》只会生成一层
RUN python -m pip install --upgrade pip &&\
python -m pip install --upgrade setuptools &&\
pip install -r requirements.txt
私有仓库 registry
1 拉取镜像
docker pull registry
2 修改配置文件
vim etc/docker/daemon.json
{
"registry-mirrors": ["https://ykibxgcr.mirror.aliyuncs.com"],
"insecure-registries": ["47.99.96.180:5000"] # 增加这个 ip 地址根据实际填写
}
3 重新加载配置
[sudo] systemctl daemon-reload
4 重启docker
[sudo] systemctl restart docker
5 创建私有仓库
docker run -id --name registry -p 5000:5000 -v /data/:/abc/data registry
6 运行私有仓库
http://47.99.96.180:5000/v2/_catalog
地址写你自己的服务器地址,如果看到下图所示,就表示创建成功了。
7 推送到私有仓库
# 给镜像打一个标签
docker tag hello-world:latest hello-world:v1
# 推
docker push hello-world:v1
docker compose
注意:
- 老版本要写version,新版本不需要
- 老版本要单独安装docker-compose,新版本docker自带docker-compose
- docker-compose中不需要定义容器名称,直接使用服务名称名称就可以访问同一个网络了。
- 如果要使用自己创建的数据卷,需要指定external: true
docker compose是由docker compose官方开源的项目,是一个定义和运行多个docker容器应用程序的工具,比如前后端分离的项目,这些服务都是彼此独立的但是又是相互有关联的,需要配合来完成工作,前端需要连接后端,后端需要连接数据库等。
这些服务之间的关联关系,就是docker compose要解决的问题。
它通过一个单独的docker-compose.yaml
的配置文件,将这一组互相关联的容器组合在一起,形成一个项目,然后使用一条命令就可以启动,停止,或重建这些服务。
需要注意的是:编写的docker-compose.yaml命令之间,一定要有空格,不然会报错。
数据卷注意
docker-compose常用命令
命令 | 描述 |
---|---|
docker-compose up | 会自动搜索当前路径下的docker-compose.yml文件并启动容器。 |
docker-compose -f |
指定文件启动容器。 |
docker-compose up -d | 以后台模式执行,不会在终端输出日志。 |
docker-compose stop | 停止容器,但不会删除容器和镜像。 |
docker-compose down | 停止容器,并删除关联的容器。 |
docker-compose start | 启动docker-compose.yml文件中管理的容器。 |
docker-compose ps | 显示正在运行的容器。 |
docker-compose images | 显示docker-compose管理的镜像。 |
docker-compose exec |
进入到docker-compose.yml文件中指定的服务容器内部。 |
docker-compose up -d --build | 启动容器并重新构建镜像,基于重新构建的镜像启动。 |
使用步骤
# 查看内核命令 arch
# 去下载对应的版本 https://github.com/docker/compose/releases
# 下载lrzsz 然后通过rz命令上传到服务器上
# 通过cp命令拷贝到 usr/local/bin/ 目录,因为该目录是环境变量所在的目录。
# 修改权限, 添加可执行权限 chmod +x usr/local/bin/docker-compose
通过docker-compose部署flask项目
2个容器,1个redis 1个flask
创建需要部署的项目
app.py
Dockerfile
requirements.txt
# app.py
from flask import Flask
from redis import Redis
app = Flask(__name__)
# 之前的写法 decode_responses 的意思是 使用utf-u去解码
# redis = Redis("127.0.0.1", port=6379, decode_responses=True)
redis = Redis(host="redis", port=6379, decode_responses=True) # 容器的主机名 --> flask容器和redis容器是能ping通的, 可以通过ip ping 也可以通过主机名 ping
@app.route("/")
def index():
redis.incr("hits") # 对名为"hits"的键进行自增操作
return f"这是您第{redis.get('hits')}次访问本站。"
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port="5001")
# Dockerfile
FROM python
WORKDIR /app
COPY . .
RUN pip install flask -i https://pypi.tuna.tsinghua.edu.cn/simple
EXPOSE 5001
CMD [ "python", "app.py" ]
编写docker-compose.yaml
# version: '3' 版本不需要写
services:
redis:
image: "redis" # image 代表镜像的名称
volumes:
- /data:/data
web:
build: # build表示构建镜像 这里的意思是在当前文件夹下找Dockerfile文件去构建镜像
context: .
dockerfile: Dockerfile
ports:
- 8080:5001 # 端口映射 宿主机:容器
environment:
- REDIS_HOST=redis # 从环境变量里面取值 就是之前的 -e 参数
volumes:
- /data:/data # 添加目录映射 即便容器删了 数据也不会丢失 主要是数据库的数据
执行命令 开始部署
docker-compose up # 前台运行
docker-compose up -d # 后台运行
通过多线程访问测试
import requests
from concurrent.futures import ThreadPoolExecutor
def run():
requests.get("http://47.99.96.180:8080/")
if __name__ == "__main__":
pool = ThreadPoolExecutor(max_workers=20)
for index in range(20000):
pool.submit(run)
pool.shutdown()
查看正在运行的docker-compose容器
注意,需要在docker-compose.yaml文件同目录中输入命令才可以,不然会报错no configuration file provided: not found