镜像(image) 包含了运行所需要的环境、配置、系统级函数库。
容器(container) 运行时有自己独立的环境,可以跨系统运行,也不需要手动再次配置环境了。这套独立运行的隔离环境我们称为容器。
Docker官方提供了一些基础镜像,然后各大软件公司又在基础镜像基础上,制作了自家软件的镜像,全部都存放在这个网站。 https://hub.docker.com/
像这种提供存储、管理Docker镜像的服务器,被称为DockerRegistry,可以翻译为镜像仓库。
Docker的官方文档 https://docs.docker.com
命令 | 说明 |
---|---|
docker pull | 拉取镜像 |
docker push | 推送镜像到DockerRegistry |
docker images | 查看本地镜像 |
docker rmi | 删除本地镜像 |
docker run | 创建并运行容器(不能重复创建) |
docker stop | 停止指定容器 |
docker start | 启动指定容器 |
docker restart | 重新启动容器 |
docker rm | 删除指定容器 |
docker ps | 查看容器 |
docker logs | 查看容器运行日志 |
docker exec | 进入容器 |
docker save | 保存镜像到本地压缩文件 |
docker load | 加载本地压缩文件到镜像 |
docker inspect | 查看容器详细信息 |
docker run -d
--name mysql
-p 3306:3306
-e TZ=Asia/Shanghai
-e MYSQL_ROOT_PASSWORD=123456
mysql
docker run 创建一个容器
-d 让容器以后台进程运行
–name mysql : 给容器起个名字叫mysql,你可以叫别的
-p 3306:3306 : 设置端口映射。 容器是隔离环境,外界不可访问。但是可以将宿主机端口映射容器内到端口,当访问宿主机指定端口时,就是在访问容器内的端口了。格式: -p 宿主机端口:容器内端口
-e 配置容器内进程运行时的一些参数。 格式: -e KEY=VALUE,KEY和VALUE都由容器内进程决定
mysql : 设置镜像名称,Docker会根据这个名字搜索并下载镜像。格式:REPOSITORY:TAG,例如mysql:8.0,其中REPOSITORY可以理解为镜像名,TAG是版本号, 在未指定TAG的情况下,默认是最新版本,也就是mysql:latest
开启容器 docker start 容器名字
关闭容器 docker stop 容器名字
删除容器 docker rm 容器名字
强制删除容器 docker rm -f 容器名字
查看容器详细信息 docker inspect 容器名字
进入容器,查看容器内目录 docker exec -it 容器名字 bash (bash表示命令行形式进入容器)
默认情况下,每次重启虚拟机我们都需要手动启动Docker和Docker中的容器。通过命令可以实现开机自启
systemctl enable docker Docker开机自启
docker update --restart=always [容器名/容器id] Docker容器开机自启
给常用Docker命令起别名,方便我们访问
# 修改/root/.bashrc文件
vi /root/.bashrc
内容如下:
# .bashrc
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias dps='docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"'
alias dis='docker images'
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
然后,执行命令使别名生效
source /root/.bashrc
数据卷(volume)是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁。
在上图中:
-我们创建了两个数据卷:conf、html
-Nginx容器内部的conf目录和html目录分别与两个数据卷关联。
-而数据卷conf和html分别指向了宿主机的/var/lib/docker/volumes/conf/_data目录和/var/lib/docker/volumes/html/_data目录
这样以来,容器内的conf和html目录就 与宿主机的conf和html目录关联起来,我们称为挂载。
此时,我们操作宿主机的/var/lib/docker/volumes/html/_data就是在操作容器内的/usr/share/nginx/html/_data目录。只要我们将静态资源放入宿主机对应目录,就可以被Nginx代理了。
命令 | 说明 |
---|---|
docker volume create | 创建数据卷 |
docker volume ls | 查看所有数据卷 |
docker volume rm | 删除指定数据卷 |
docker volume inspect | 查看某个数据卷的详情 |
docker volume prune | 清除数据卷 |
注意:容器与数据卷的挂载要在创建容器时配置,对于创建好的容器,是不能设置数据卷的。而且创建容器的过程中,数据卷会自动创建。
# 1.首先创建容器并指定数据卷,注意通过 -v 参数来指定数据卷
docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx
# 2.然后查看数据卷
docker volume ls
# 结果
DRIVER VOLUME NAME
local 737adda91121f58d957d73d7304f059b5ff07cbd7ef6d04edbd398e1809afd8f
local html
# 3.查看数据卷详情
docker volume inspect html
# 结果
[
{
"CreatedAt": "2023-11-26T14:01:36+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/html/_data",
"Name": "html",
"Options": null,
"Scope": "local"
}
]
# 4.查看/var/lib/docker/volumes/html/_data目录
ll /var/lib/docker/volumes/html/_data
# 可以看到与nginx的html目录内容一样,结果如下:
总用量 8
-rw-r--r--. 1 root root 497 12月 28 2021 50x.html
-rw-r--r--. 1 root root 615 12月 28 2021 index.html
# 5.进入该目录,并随意修改index.html内容
cd /var/lib/docker/volumes/html/_data
vi index.html
# 6.打开页面,查看效果
192.168.133.128:80 ip地址:80
# 7.进入容器内部,查看/usr/share/nginx/html目录内的文件是否变化
docker exec -it nginx bash
注意:每一个不同的镜像,将来创建容器后内部有哪些目录可以挂载,可以参考DockerHub对应的页面
数据卷的目录结构较深,如果我们去操作数据卷目录会不太方便。在很多情况下,我们会直接将容器目录与宿主机指定目录挂载。挂载语法与数据卷类似:
# 挂载本地目录
-v 本地目录:容器内目录
# 挂载本地文件
-v 本地文件:容器内文件
本地挂载 都是 ./ 开头
-v mysql:/var/lib/mysql # 会被识别为一个数据卷叫mysql,运行时会自动创建这个数据卷
-v ./mysql:/var/lib/mysql # 会被识别为当前目录下的mysql目录,运行时如果不存在会创建目录
案列如下:
- 挂载/root/mysql/data到容器内的/var/lib/mysql目录
- 挂载/root/mysql/init到容器内的/docker-entrypoint-initdb.d目录(初始化的SQL脚本目录)
- 挂载/root/mysql/conf到容器内的/etc/mysql/conf.d目录(这个是MySQL配置文件目录)
# 1.删除原来的MySQL容器
docker rm -f mysql
# 2.进入root目录
cd ~
# 3.创建并运行新mysql容器,挂载本地目录
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123456 \
-v ./mysql/data:/var/lib/mysql \
-v ./mysql/conf:/etc/mysql/conf.d \
-v ./mysql/init:/docker-entrypoint-initdb.d \
mysql
# 4.查看root目录,可以发现~/mysql/data目录已经自动创建好了
ls -l mysql
# 结果:
总用量 4
drwxr-xr-x. 2 root root 20 11月 26 14:17 conf
drwxr-xr-x. 7 polkitd root 4096 11月 26 14:22 data
drwxr-xr-x. 2 root root 23 11月 26 14:17 init
# 查看data目录,会发现里面有大量数据库数据,说明数据库完成了初始化
ls -l data
# 5.查看MySQL容器内数据
# 5.1.进入MySQL
docker exec -it mysql mysql -uroot -p123456
# 5.2.查看编码表
show variables like "%char%";
# 5.3.结果,发现编码是utf8mb4没有问题
+--------------------------+--------------------------------+
| Variable_name | Value |
+--------------------------+--------------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8mb3 |
| character_sets_dir | /usr/share/mysql-8.0/charsets/ |
+--------------------------+--------------------------------+
# 6.查看数据
# 6.1.查看数据库
show databases;
# 结果,hmall是黑马商城数据库
+--------------------+
| Database |
+--------------------+
| hmall |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
# 6.2.切换到hmall数据库
use hmall;
# 6.3.查看表
show tables;
# 结果:
+-----------------+
| Tables_in_hmall |
+-----------------+
| address |
| cart |
| item |
| order |
| order_detail |
| order_logistics |
| pay_order |
| user |
+-----------------+
# 6.4.查看address表数据
+----+---------+----------+--------+----------+-------------+---------------+-----------+------------+-------+
| id | user_id | province | city | town | mobile | street | contact | is_default | notes |
+----+---------+----------+--------+----------+-------------+---------------+-----------+------------+-------+
| 59 | 1 | 北京 | 北京 | 朝阳区 | 13900112222 | 金燕龙办公楼 | 李佳诚 | 0 | NULL |
| 60 | 1 | 北京 | 北京 | 朝阳区 | 13700221122 | 修正大厦 | 李佳红 | 0 | NULL |
| 61 | 1 | 上海 | 上海 | 浦东新区 | 13301212233 | 航头镇航头路 | 李佳星 | 1 | NULL |
| 63 | 1 | 广东 | 佛山 | 永春 | 13301212233 | 永春武馆 | 李晓龙 | 0 | NULL |
+----+---------+----------+--------+----------+-------------+---------------+-----------+------------+-------+
4 rows in set (0.00 sec)
镜像就是一堆文件的集合,但需要注意的是,镜像文件不是随意堆放的,而是按照操作的步骤分层叠加而成,每一层形成的文件都会单独打包并标记一个唯一id,称为Layer(层)。
如果我们构建时用到的某些层其他人已经制作过,就可以直接拷贝使用这些层,而不用重复制作。
由于制作镜像的过程中,需要逐层处理和打包,比较复杂,所以Docker就提供了自动打包镜像的功能。我们只需要将打包的过程,每一层要做的事情用固定的语法写下来,交给Docker去执行即可。
而这种记录镜像结构的文件就称为Dockerfile。
指令 | 说明 |
---|---|
FROM | 指定基础镜像 |
ENV | 设置环境变量,可在后面指令使用 |
COPY | 拷贝本地文件到镜像的指定目录 |
RUN | 执行Linux的shell命令,一般是安装过程的命令 |
EXPOSE | 指定容器运行时监听的端口,是给镜像使用者看的 |
ENTRYPOINT | 镜像中应用的启动命令,容器运行时调用 |
例如,要基于Ubuntu镜像来构建一个Java应用,其Dockerfile内容如下
# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK的安装目录、容器内时区
ENV JAVA_DIR=/usr/local
ENV TZ=Asia/Shanghai
# 拷贝jdk和java项目的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./docker-demo.jar /tmp/app.jar
# 设定时区
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 安装JDK
RUN cd $JAVA_DIR \
&& tar -xf ./jdk8.tar.gz \
&& mv ./jdk1.8.0_144 ./java8
# 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8
ENV PATH=$PATH:$JAVA_HOME/bin
# 指定项目监听的端口
EXPOSE 8080
# 入口,java项目的启动命令
ENTRYPOINT ["java", "-jar", "/app.jar"]
有人提供了基础的系统加JDK环境,我们在此基础上制作java镜像,就可以省去JDK的配置了
# 基础镜像
FROM openjdk:11.0-jre-buster
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝jar包
COPY docker-demo.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]
# 进入镜像目录
cd /root/demo
# 开始构建
docker build -t docker-demo:1.0 .
- docker build : 就是构建一个docker镜像
- -t docker-demo:1.0 :-t参数是指定镜像的名称(repository和tag)
- . : 最后的点是指构建时Dockerfile所在路径,由于我们进入了demo目录,所以指定的是.代表当前目录
# 直接指定Dockerfile目录
docker build -t docker-demo:1.0 /root/demo
命令 | 说明 |
---|---|
docker network create | 创建一个网络 |
docker network ls | 查看所有网络 |
docker network rm | 删除指定网络 |
docker network prune | 清除未使用的网络 |
docker network connect | 使指定容器连接加入某网络 |
docker network disconnect | 使指定容器连接离开某网络 |
docker network inspect | 查看网络详细信息 |
# 1.首先通过命令创建一个网络
docker network create tz
# 2.然后查看网络
docker network ls
# 结果:
NETWORK ID NAME DRIVER SCOPE
2c5e03895cfe bridge bridge local
6ac65b1b8001 host host local
719239a1884c none null local
ee40d1556b1c tz bridge local
# 其中,除了tz以外,其它都是默认的网络
# 3.让nginx和mysql都加入该网络,注意,在加入网络时可以通过--alias给容器起别名
# 这样该网络内的其它容器可以用别名互相访问!
# 3.1.mysql容器,指定别名为db,另外每一个容器都有一个别名是容器名
docker network connect tz mysql --alias db
# 3.2.nginx容器
docker network connect tz nginx
# 4.进入nginx容器,尝试利用别名访问db
# 4.1.进入容器
docker exec -it nginx bash
# 4.2.用db别名访问
ping db
# 结果
PING db (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql.tz (172.18.0.2): icmp_seq=1 ttl=64 time=0.147 ms
64 bytes from mysql.tz (172.18.0.2): icmp_seq=2 ttl=64 time=0.334 ms
64 bytes from mysql.tz (172.18.0.2): icmp_seq=3 ttl=64 time=0.242 ms
64 bytes from mysql.tz (172.18.0.2): icmp_seq=4 ttl=64 time=0.252 ms
# 4.3.用容器名访问
ping mysql
# 结果:
64 bytes from mysql.tz (172.18.0.2): icmp_seq=1 ttl=64 time=0.131 ms
64 bytes from mysql.tz (172.18.0.2): icmp_seq=2 ttl=64 time=0.055 ms
64 bytes from mysql.tz (172.18.0.2): icmp_seq=3 ttl=64 time=0.071 ms
64 bytes from mysql.tz (172.18.0.2): icmp_seq=4 ttl=64 time=0.331 ms
解决没有ping命令问题
首先 进入容器内 docker exec -it 容器名字 bash
然后 执行命令 apt-get update #获取更新软件源
最后 执行命令 apt install iputils-ping #安装ping命令
注意:apt-get update apt install iputils-ping都是在容器内执行的命令