容器
去运行,避免相互干扰打包
,形成可移植镜像隔离
模拟
硬件设备,然后运行另一个操作系统。例如在Windows系统中运行CentOS系统,就可以运行任意的CentOS应用了特性 | Docker | 虚拟机 |
---|---|---|
性能 | 接近原生 | 性能较差 |
硬盘占用 | 一般为MB | 一般为GB |
启动 | 秒级 | 分钟级 |
镜像(Image)
:Docker将应用程序及其所需要的依赖、函数库、环境、配置等文件打包在一起,称为镜像容器(Container)
:镜像中的应用程序形成后的进程就是容器
,只是Docker会给容器进程做隔离,对外不可见镜像
,就是吧一个应用在硬盘上的文件、机器运行环境、部分系统函数库文件一起打包成的文件包。这个文件包是只读的(防止你对镜像文件进行修改/污染,从而导致镜像不可用,容器从镜像中拷贝一份文件到自己的空间里来写数据)容器
呢,就是把这些文件中编写的程序、函数加载到内存中允许形成进程,只不过要隔离起来。因此一个镜像可以启动多次,形成多个容器进程。Docker 分为 CE 和 EE 两大版本。CE 即社区版,免费,支持周期 7 个月;EE 即企业版,强调安全,付费使用,支持周期 24 个月。
Docker CE 分为 stable
test
和 nightly
三个更新频道。
官方网站上有各种环境下的 安装指南,这里主要介绍 Docker CE 在 CentOS上的安装。
Docker CE 支持 64 位版本 CentOS 7,并且要求内核版本不低于 3.10
CentOS 7满足最低内核要求,本文也是在CentOS 7安装Docker
如果之前安装过旧版本的Docker,可以使用下面命令卸载
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
yum install -y yum-utils \
device-mapper-persistent-data \
lvm2 --skip-broken
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io
# 关闭
systemctl stop firewalld
# 禁止开机启动防火墙
systemctl disable firewalld
#查看防火墙的状态
systemctl status firewalld
# 启动docker服务
systemctl start docker
# 停止docker服务
systemctl stop docker
# 重启docker服务
systemctl restart docker
#设置docker开机自启动
sudo systemctl enable docker
[root@lsc1 ~]# docker -v
Docker version 24.0.4, build 3713ee1
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://x4ldcyqu.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
tee
命令基于标准输入读取数据,标准输出或文件写入数据首先来看下镜像的名称组成:
镜像名称一般分为两部分:[repository]:[tag]
例如
mysql:5.7
,这里的mysql就是repository,5.7就是tag,合在一起就是镜像名称,代表5.7版本的MySQL镜像
在没有指定tag时,默认是latest,代表最新版本的镜像,例如mysql:latest
在这个案例,我们来联系拉取、查看镜像
需求:从DockerHub中拉取一个Nginx镜像并查看
2.根据查看到的镜像名称,拉取自己需要的镜像,通过命令:docker pull nginx
拉取最新的nginx镜像
[root@lsc1 ~]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
a2abf6c4d29d: Already exists
a9edb18cadd1: Pull complete
589b7251471a: Pull complete
186b1aaa4aa6: Pull complete
b4df32aa5a72: Pull complete
a0bcbecc962e: Pull complete
Digest: sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
3.通过命令docker images
查看拉取到的镜像
[root@lsc1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 20 months ago 141MB
docker save
将nginx镜像导出磁盘,然后在通过docker load
加载回来docker xx --help
命令查看docker save
和docker load
的语法[root@localhost ~]# docker save --help Usage: docker save [OPTIONS] IMAGE [IMAGE...] Save one or more images to a tar archive (streamed to STDOUT by default) Options: -o, --output string Write to a file, instead of STDOUT
命令格式:
docker save -o [保存的目标文件名称] [镜像名称]
[root@localhost ~]# docker load --help Usage: docker load [OPTIONS] Load an image from a tar archive or STDIN Options: -i, --input string Read from tar archive file, instead of STDIN -q, --quiet Suppress the load output
命令格式:
docker load -i [镜像压缩文件名]
2使用docker save导出镜像到磁盘,随后使用ls命令可以查看到nginx.tar文件
docker save -o nginx.tar nginx:latest
3使用docker load加载镜像,在此之前,我们使用命令删除本地nginx镜像
[root@lsc1 tmp]# docker rmi nginx:latest # rmi是remove image的缩写
Untagged: nginx@sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Deleted: sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85
Deleted: sha256:b625d8e29573fa369e799ca7c5df8b7a902126d2b7cbeb390af59e4b9e1210c5
Deleted: sha256:7850d382fb05e393e211067c5ca0aada2111fcbe550a90fed04d1c634bd31a14
Deleted: sha256:02b80ac2055edd757a996c3d554e6a8906fd3521e14d1227440afd5163a5f1c4
Deleted: sha256:b92aa5824592ecb46e6d169f8e694a99150ccef01a2aabea7b9c02356cdabe7c
Deleted: sha256:780238f18c540007376dd5e904f583896a69fe620876cabc06977a3af4ba4fb5
4随后运行命令,加载本地文件
[root@lsc1 tmp]# docker load -i nginx.tar
e379e8aedd4d: Loading layer [==================================================>] 62MB/62MB
b8d6e692a25e: Loading layer [==================================================>] 3.072kB/3.072kB
f1db227348d0: Loading layer [==================================================>] 4.096kB/4.096kB
32ce5f6a5106: Loading layer [==================================================>] 3.584kB/3.584kB
d874fd2bc83b: Loading layer [==================================================>] 7.168kB/7.168kB
Loaded image: nginx:latest
unpause
命令恢复,内存空间被恢复,程序继续运行。docker rm
是将文件系统也彻底删除,也就是将容器彻底删除掉了docker run
:创建并运行一个容器,处于运行状态docker pause
:让一个运行的容器暂停docker unpause
:让一个容器从暂停状态恢复运行docker stop
:停止一个运行的容器docker start
:让一个停止的容器再次运行docker rm
:删除一个容器创建并运行nginx容器的命令
docker run --name containerName -p 80:80 -d nginx
命令解读
docker run
:创建并运行一个容器--name
:给容器起一个名字,例如叫做myNginx-p
:将宿主机端口与容器端口映射,冒号左侧是宿主机端口,右侧是容器端口-d
:后台运行容器nginx
:镜像名称,例如nginx这里的-p
参数,是将容器端口映射到宿主机端口
那我们再浏览器输入虚拟机ip:80就能看到nginx默认页面了
需求:进入Nginx容器,修改HTML文件内容,添加
Welcome To My Blog!
提示:进入容器要用到docker exec
命令[root@lsc1 ~]# docker exec --help Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...] Execute a command in a running container Aliases: docker container exec, docker exec Options: -d, --detach Detached mode: run command in the background --detach-keys string Override the key sequence for detaching a container -e, --env list Set environment variables --env-file list Read in a file of environment variables -i, --interactive Keep STDIN open even if not attached --privileged Give extended privileges to the command -t, --tty Allocate a pseudo-TTY -u, --user string Username or UID (format: "
[: ) -w, --workdir string Working directory inside the container]"
1 进入容器。进入刚刚我们创建好的nginx容器
docker exec -it nginx bash
docker exec
:进入容器内部,执行一个命令-it
:给当前进入的容器创建一个标准输入、输出终端,允许我们与容器交互nginx
:要进入的容器名称bash
:进入容器后执行的命令,bash是一个linux终端交互命令2 进入nginx的HTML所在目录
/usr/share/nginx/html
root@e34e51c88698:/# cd /usr/share/nginx/html
root@e34e51c88698:/usr/share/nginx/html# ls
50x.html index.html
3 修改index.html的内容
容器内没有vi命令,无法直接修改,我们使用下面的命令来修改
sed -i -e 's#Welcome to nginx#Welcome To My Blog#g' index.html
docker run
命令常见的参数有哪些?
--name
:指定容器名称-p
:指定端口映射-d
:让容器后台运行docker logs
-f
参数可以持续查看日志docker ps
docker ps -a
查看所有容器,包括已停止的数据卷操作的基本语法如下
docker volume [COMMAND]
docker volume 命令是数据卷操作,根据命令后跟随的command来确定下一步的操作
create
:创建一个volumeinspect
:显示一个或多个volume的信息ls
:列出所有的volumeprune
:删除未使用的volumerm
:删除一个或多个指定的volume需求:创建一个数据卷,并查看数据卷在宿主机的目录位置
创建数据卷
docker volume create html
查看所有数据
docker volume ls
结果
[root@lsc1 ~]# docker volume ls
DRIVER VOLUME NAME
local 6a802c9f0640a63873103f2a4e3ee7a97388751bf2ab40a58aff549cb265e9fa
local a8c27a88d4706628e2012de6f8e5bb5108e9f029936c800fccbda10ba8da59ff
local html
查看数据卷详细信息卷
docker volume inspect html
结果
[root@localhost ~]# docker volume inspect html
[
{
"CreatedAt": "2022-12-19T12:51:54+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/html/_data",
"Name": "html",
"Options": {},
"Scope": "local"
}
]
可以看到我们创建的html这个数据卷关联的宿主机目录为
/var/lib/docker/volumes/html/_data
需求:创建一个nginx容器,修改容器内的html
目录的index.html
内容
/usr/share/nginx/html
,我们需要把这个目录挂载到html
这个数据卷上,方便操作其中的内容-v
参数挂载数据卷1创建容器并挂载数据卷到容器内的HTML目录
[root@lsc1 ~]# docker run --name nginx -v html:/usr/share/nginx/html -p 80:80 -d nginx
7d5098ba11e1e12cfe05cbe1a1e4a75789f25514bbea238b7b42b1b16c43af01
2进入html数据卷所在位置,并修改HTML内容
# 查看数据卷位置
docker volume inspect html
# 进入该目录
cd /var/lib/docker/volumes/html/_data
# 修改文件
vi index.html
# 也可以在FinalShell中使用外部编译器(例如VSCode)来修改文件
需求:创建并运行一个MySQL容器,将宿主机目录直接挂载到容器
sudo docker pull mysql:5.7
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=root \
-d mysql:5.7
指令 | 说明 | 示例 |
---|---|---|
FROM | 指定基础镜像 | FROM centos:6 |
ENV | 设置环境变量,可在后面指令使用 | ENV key value |
COPY | 拷贝本地文件到镜像的指定目录 | COPY ./mysql-5.7.rpm /tmp |
RUN | 执行Linux的shell命令,一般是安装过程的命令 | RUN yum install gcc |
EXPOSE | 指定容器运行时监听的端口,是给镜像使用者看的 | EXPOSE 8080 |
ENTRYPOINT | 镜像中应用的启动命令,容器运行时调用 | ENTRYPOINTjava -jar xxjar |
需求:基于Ubuntu镜像构建一个新镜像,运行一个Java项目
创建一个空文件夹docker-demo
mkdir /tmp/docker-demo
将docker-demo.jar文件拷贝到docker-demo这个目录
拷贝jdk8.tar.gz文件到docker-demo这个目录
在docker-demo目录下新建Dockerfile,并写入以下内容
# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK的安装目录
ENV JAVA_DIR=/usr/local
# 拷贝jdk的到JAVA_DIR目录下
COPY ./jdk8.tar.gz $JAVA_DIR/
# 安装JDK
RUN cd $JAVA_DIR && tar -xf ./jdk8.tar.gz && mv ./jdk1.8.0_44 ./java8
# 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8
ENV PATH=$PATH:$JAVA_HOME/bin
# 拷贝java项目的包到指定目录下,我这里是/tmp/app.jar
COPY ./docker-demo.jar /tmp/app.jar
# 暴露端口,注意这里是8090端口,如果你之前没有关闭防火墙,请关闭防火墙或打开对应端口,云服务器同理
EXPOSE 8090
# 入口,java项目的启动命令
ENTERPOINT java -jar /tmp/app.jar
在docker-demo目录下使用
docker build -t docker_demo:1.0 .
使用docker images命令,查看镜像
[root@localhost docker-demo]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker_demo 1.0 c8acd2dd02cf About a minute ago 722MB
redis latest 29ab4501eac3 2 days ago 117MB
nginx latest 3964ce7b8458 5 days ago 142MB
ubuntu 16.04 b6f507652425 15 months ago 135MB
mysql 5.7.25 98455b9624a9 3 years ago 372MB
创建并运行一个docker_demo容器
docker run --name testDemo -p 8090:8090 -d docker_demo:1.0
浏览器访问http://192.168.128.130:8090/hello/count,即可看到页面效果(注意修改虚拟机ip)
需求:基于java:8-alpine镜像,将一个Java项目构建为镜像
新建一个空目录(或者继续使用/tmp/docker-demo
目录)
将docker-demo.jar复制到该目录下(继续使用刚刚的目录就不用管)
在目录中新建一个文件,命名为Dockerfile,并编写该文件(修改为如下样子就好)
# 将openjdk:8作为基础镜像
FROM openjdk:8
# 拷贝java项目的包到指定目录下,我这里是/tmp/app.jar
COPY ./docker-demo.jar /tmp/app.jar
# 暴露端口
EXPOSE 8090
# 入口
ENTRYPOINT java -jar /tmp/app.jar
构建镜像
docker build -t docker_demo:2.0 .
创建并运行一个docker_demo容器(在此之前停止之前的docker_demo容器)
docker run --name testDemo02 -p 8090:8090 -d docker_demo:2.0
浏览器访问http://192.168.200.138:8090/hello/count,即可看到页面效果
Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行,格式如下
version: "3.8"
services:
# docker run --name mysql \
# -e MYSQL_ROOT_PASSWORD=root \
# -p 3306:3306 \
# -v /tmp/mysql/data:/var/lib/mysql \
# -v /tmp/mysql/conf/myCnf.cf:/etc/mysql/conf.d/myCnf.cnf \
# -d \
# mysql:5.7
mysql: # 对应docker run中的 --name
image: mysql:5.7 # 对应docker run中最后声明的镜像
enviroment: # 对应docker run中的 -e MYSQL_ROOT_PASSWIRD=root
MYSQL_ROOT_PASSWORD: root
volumes: # 对应docker run中的 -v /tmp/mysql/data:/var/lib/mysql
- "/tmp/mysql/data:/var/lib/mysql"
- "/tmp/mysql/conf/myCnf.cf:/etc/mysql/conf.d/myCnf.cnf"
# 这里并不需要-d参数来后台运行,因为此种方法默认就是后台运行
# 同时也不需要暴露端口,在微服务集群部署中,MySQL仅仅是供给给集群内的服务使用的,所以不需要对外暴露端口
# 临时构建镜像并运行,下面的配置文件包含了docker build和docker run两个步骤
# docker build -t web:1.0 .
# docker run --name web -p 8090:8090 -d web:1.0
web:
build: .
ports:
- "8090:8090"
上面的Compose文件就描述一个项目,其中包含两个容器:
mysql
:一个基于mysql:5.7镜像构建的容器,并且挂载了两个项目web
:一个基于docker build
临时构建的镜像容器,映射端口为8090
DockerCompose的详细语法请参考官网:https://docs.docker.com/compose/compose-file/
其实DockerCompose文件可以看做是将多个docker run命令写到一个文件,只是语法稍有差异
在Linux下使用命令下载
# 安装
curl -L https://github.com/docker/compose/releases/download/1.23.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
修改文件权限
chmod +x /usr/local/bin/docker-compose
Base自动补全命令
curl -L https://raw.githubusercontent.com/docker/compose/1.29.1/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose
如出现错误,需要修改自己的hosts文件
Failed connect to raw.githubusercontent.com:443; Connection refused
echo "199.232.68.133 raw.githubusercontent.com" >> /etc/hosts
如出现新错误,重复发起命令,多试几次
TCP connection reset by peer
需求:将之前学习的cloud-demo微服务集群利用DockerCompose部署
docker-compose up -d
来部署针对我们之前写的cloud-demo,来编写对应的docker-compose文件
version: "3.2"
services:
nacos:
image: nacos/nacos-server
environment:
MDOE: standalone
ports:
- "8848:8848"
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: 123456
volumes:
- "$PWD/mysql/data:/var/lib/mysql" # 这里的$PWD是执行linux命令,获取当前目录
- "$PWD/mysql/conf:/etc/mysql/conf.d"
userservice:
build: ./user-service
orderservice:
build: ./order-service
gateway:
build: ./gateway
poets:
- "10010:10010"
其中包含了5个服务:
使用Docker Compose部署时,所有的服务之间都可以用服务名互相访问,那我们现在就需要修改我们cloud-demo中的yml配置文件,如下
spring:
cloud:
nacos:
# server-addr: localhost:80 #Nacos地址
server-addr: nacos:8848 # 使用compose中的服务名来互相访问,用nacos替换localhost
config:
file-extension: yaml # 文件后缀名
将我们修改好的代码打包,注意修改pom文件指定打包名为app
<build>
<finalName>appfinalName>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
之后使用maven工具打包
最终的目录结构如下
将cloud-demo上传到虚拟机,进入目录,执行以下命令
docker-compose up -d
启动之后查看日志,会发现日志中报错
com.alibaba.nacos.api.exception.NacosException: failed to req API:/nacos/v1/ns/instance/list after all servers([nacos:8848]) tried: java.net.ConnectException: Connection refused (Connection refused)
docker-compose logs -f
阿里巴巴nacos连接失败,其原因是userservice在nacos之前启动了,而nacos启动太慢了,userservice注册失败,而且也没有重试机制(等nacos启动完成后,重试注册,就可以避免这个问题)
所以建议nacos单独先启动,其他服务后启动,我这里的解决方案是重启另外三个服务
重启gateway userservice orderservice服务
docker-compose restart gateway userservice orderserivce
查看userservice启动日志,这次就不报错了
docker-compose logs -f userservice
打开浏览器访问http://192.168.128.130:10010/user/1?authorization=admin, 也可以看到数据