不用重复使用docker run命令,这是创建容器命令,启动容器应该是docker start;
docker ps 查看进程运行状态;
docker rmi 删除镜像、rm 删除容器;
docker logs 查看日志、docker exec 执行命令进入容器内部;
案例
# 第1步,去DockerHub查看nginx镜像仓库及相关信息
# 第2步,拉取Nginx镜像
docker pull nginx
# 第3步,查看镜像
docker images
# 第4步,创建并允许Nginx容器
docker run -d --name nginx -p 80:80 nginx
# 第5步,查看运行中容器
docker ps
# 也可以加格式化方式访问,格式会更加清爽
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"
# 第6步,访问网页,地址:http://虚拟机地址
# 第7步,停止容器
docker stop nginx
# 第8步,查看所有容器
docker ps -a --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"
# 第9步,再次启动nginx容器
docker start nginx
# 第10步,再次查看容器
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"
# 第11步,查看容器详细信息
docker inspect nginx
# 第12步,进入容器,查看容器内目录
docker exec -it nginx bash
# 或者,可以进入MySQL
docker exec -it mysql mysql -uroot -p
# 第13步,删除容器
docker rm nginx
# 运行中的容器无法删除,可以先停止再删除
docker stop nginx
# 发现无法删除,因为容器运行中,强制删除容器
docker rm -f nginx
镜像常规命令
# 打包镜像
docker save -o nginx.tar nginx:latest
# 删除镜像
docker rmi nginx:latest
# 导入镜像
docker load -i nginx.tar
容器常规命令
# 创建容器
docker run -d --name nginx -p 80:80 nginx
# 查看运行中容器
docker ps
# 也可以加格式化方式访问,格式会更加清爽
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"
# 容器停止
docker stop nginx
# 容器启动
docker start nginx
# 查看所有的容器(未启动包括在内)
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}" -a
查看日志
# 持续输出日志,ctrl c停止
docker logs -f nginx
找到root目录下的bashrc的文件
vi ~/.bashrc
# 或者
vi /root/.bashrc
添加一个别名
alias dps='docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"'
保存:wq,执行以下命令使别名生效
source /root/.bashrc
# 或者
source ~/.bashrc
问题引入,容器是隔离环境,容器内程序的文件、配置、运行时产生的容器都在容器内部,我们要读写容器内的文件非常不方便。
以上问题都说明,容器提供程序的运行环境,但是程序运行产生的数据、程序运行依赖的配置都应该与容器解耦。
数据卷(volume)是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁
Nginx有两个关键目录:
但是这些文件均在容器内部,所以必须利用数据卷将两个目录与宿主机目录关联,方便操作
创建的数据卷conf、html和nginx容器中的两个目录关联;
数据卷分别指向宿主机/var/lib/docker/volumes/conf/_data目录和/var/lib/docker/volumes/html/_data目录;
这样容器内的目录就和宿主机的目录关联起来了,成为挂载;
此时操作宿主机的/var/lib/docker/volumes/html/_data就是在操作容器内的/usr/share/nginx/html/_data目录。只要我们将静态资源放入宿主机对应目录,就可以被Nginx代理了。
在执行docker run命令时,使用 -v 数据卷名:容器内目录 可以完成数据卷挂载;
当创建容器时,如果挂载了数据卷且数据卷不存在,会自动创建数据卷;
# 1.首先创建容器并指定数据卷,注意通过 -v 参数来指定数据卷
docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx
# 2.然后查看数据卷
docker volume ls
# 3.查看数据卷详情
docker volume inspect html
# 4.查看/var/lib/docker/volumes/html/_data目录
ll /var/lib/docker/volumes/html/_data
# 可以看到与nginx的html目录内容一样
# 5.进入该目录,并随意修改index.html内容
cd /var/lib/docker/volumes/html/_data
vi index.html
# 6.打开页面,查看效果
# 7.进入容器内部,查看/usr/share/nginx/html目录内的文件是否变化
docker exec -it nginx bash
查看mysql容器是否有数据卷挂载
# 1.查看MySQL容器详细信息
docker inspect mysql
# 关注其中.Config.Volumes部分和.Mounts部分
发现容器是有数据卷,但是创建容器mysql时并没有使用-v参数,这是因为容器声明了一个本地目录,需要挂载数据卷,但是数据卷未定义,所以这是匿名卷;
当想对mysql容器进行版本升级,此时删除容器,再创建一个mysql最新版本的容器且不指定自定义数据卷,同样会生成一个非常长的名称的匿名卷,到时候做数据迁移不太方便,可以但是不方便,所以使用自定义卷而不是匿名卷;
基于宿主机目录实现mysql数据目录、配置文件、初始化脚本的挂载;
方法与之前创建数据卷的方式相似,执行docker run 命令时,使用-v 本地目录:容器目录 就可以完成本地目录挂载;
注意:本地目录或文件必须以 / 或 ./开头,如果直接以名字开头,会被识别为数据卷名而非本地目录名。
-v mysql:/var/lib/mysql # 会被识别为一个数据卷叫mysql,运行时会自动创建这个数据卷
-v ./mysql:/var/lib/mysql # 会被识别为当前目录下的mysql目录,运行时如果不存在会创建目录
先删除之前的mysql容器,先创建这三个目录;
docker rm -f mysql
# 创建mysql目录
mkdir mysql
cd mysql
# 创建3个目录
mkdir data
mkdir conf
mkdir init
将下载好的conf和init文件直接拖到root目录下(Xftp7软件)
运行本地目录挂载命令
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
-v /root/mysql/data:/var/lib/mysql \
-v /root/mysql/conf:/etc/mysql/conf.d \
-v /root/mysql/init:/docker-entrypoint-initdb.d \
mysql
制作自己的Java项目镜像
镜像中包含了程序运行需要的系统函数库、环境、配置、依赖;
所以自定义镜像也就需要配备项目的基础环境、依赖、配置等文件;
上述步骤中的每一次操作其实都是在生产一些文件(系统运行环境、函数库、配置最终都是磁盘文件),所以镜像就是一堆文件的集合;
镜像文件不是随意堆放的,而是按照操作的步骤分层叠加而成,每一层形成的文件都会单独打包并标记一个唯一id,称为Layer(层);
构建时如果某些层其他人制作过,可以直接拷贝使用这些层,无需重复制作,例如,第一步中需要的Linux运行环境,通用性就很强,所以Docker官方就制作了这样的只包含Linux运行环境的镜像。在制作java镜像时,就无需重复制作,直接使用Docker官方提供的CentOS或Ubuntu镜像作为基础镜像;
docker提供自动打包镜像的功能,无需自己逐级处理和打包,只需提供每一层要做的事情,用固定语法写下来,交给docker执行即可;
实现容器之间的访问
但是,容器内的IP实质上是一个虚拟IP,并不固定,如果该容器停止,另一个容器启动,很可能IP就被其它容器占用,此时如果开发时写死了IP,那么连接就会失败;
所以引出docker的网络功能来解决这个问题;
# 1.首先通过命令创建一个网络
docker network create hmall
# 2.然后查看网络
docker network ls
# 结果:
NETWORK ID NAME DRIVER SCOPE
639bc44d0a87 bridge bridge local
403f16ec62a2 hmall bridge local
0dc0f72a0fbb host host local
cd8d3e8df47b none null local
# 其中,除了hmall以外,其它都是默认的网络
# 3.让dd和mysql都加入该网络,注意,在加入网络时可以通过--alias给容器起别名
# 这样该网络内的其它容器可以用别名互相访问!
# 3.1.mysql容器,指定别名为db,另外每一个容器都有一个别名是容器名
docker network connect hmall mysql --alias db
# 3.2.db容器,也就是我们的java项目
docker network connect hmall dd
# 3.3.也可以在新建容器阶段就接入网络
docker run -d --name demo -p 8080:8080 --network hmall docker-demo
docker run -d --name nginx_demo -p 80:80 --network nxj nginx
# 4.进入dd容器,尝试利用别名访问db
# 4.1.进入容器
docker exec -it dd bash
# 4.2.用db别名访问
ping db
# 结果
PING db (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=2 ttl=64 time=0.056 ms
# 4.3.用容器名访问
ping mysql
# 结果:
PING mysql (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=2 ttl=64 time=0.054 ms