docker 的个人理解与使用
反正docker 是个好东西
官方文档一定要啃一下!!!我是从这开始的https://docs.docker.com/get-started
个人建议先学好基础的命令,然后配合docker desktop
客户端,可以直观的体现和调整。
文章目录
一、docker是什么?
docker 就如他的图标一样可以理解为一个运输集装箱的一艘船,船就是你当前的系统(Ubuntu,centeros等),集装箱就是docker镜像创建的容器,容器运行也需要完整的环境,但是因为你的操作系统有了环境,容器就可以共享环境,只需要部分特有代码即可运行,下面我用个人觉得比较通俗的说法说一下。docker 有三个东西:镜像,容器,仓库。
镜像是容器的模板,照着镜像然后配置一些参数做一个容器,容器就是产品可以使用,仓库就是存储镜像的git。比如php:8.2-fpm-alpine镜像,看名称可以得出这是一个基于alpine系统制作的php-fpm8.2镜像,如果你是在如centeros的系统上运行容器,其本身就是Linux系统,所有部分底层公用,只需要下载php-fpm8.2的代码即可。(个人理解啊,手动狗头)
二、实践
docker安装这个很容易大家百度一下即可,这里就不复述了哈哈哈哈。安装且启动后在终端中打docker会有对应的提示。docker相关操作通过终端中以docker开头命令操作。
我下面的操作是在腾讯云的Ubuntu环境的root权限下进行,且在腾讯云中开放了对应的端口可以被外网访问
1、使用别人的镜像
1.1、单应用
docker run --name mysql5744 \
-dp 3306:3306
-v mysql-data:/var/lib/mysql \
-v /opt/gitProject/yjybase/mysql:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=123456
mysql:5.7.44
上面代码是运行一个名称(--name
)为mysql5744
的应用。
进程守护的方式运行(后端运行)-d
。
p
表示宿主机对外暴露的接口为3306,容器的暴露端口也为3306。
-v
挂载一个叫mysql-data
卷用来存储在容器地址/var/lib/mysql
中的数据。
再将宿主机中/opt/gitProject/yjybase/mysql
文件夹与容器内地址/etc/mysql/conf.d
进行绑定。
-e
将容器中MYSQL_ROOT_PASSWORD
的变量值设置为123456
。
最后的mysql:5.7.44
表示以上操作是基于mysql的5.7.44版本镜像。
正确运行后输入docker ps
出现如下
表示这个容器运行成功,接下来就可以使用mysql的客户端工具连接这个mysql了。
简单的解释一下上面的两个-v
因为mysql是运行在容器中的,如果容器被删除了对应的数据就没了,所以我们需要把它拿出来。一个我用的是一个名称,一个我用的是我服务器中的地址,叫法也分别是叫券的挂载
和绑定
,券
是由docker管理在/var/lib/docker/volumes/
下面
至于为什么将其与/var/lib/mysql
对应,这个需要去看镜像使用说明(https://hub.docker.com/
,23年5月份开始就上不去了,需要你们自己想办法,或者使用这个https://gallery.ecr.aws/search?page=1
这个可以参考,因为可能里面的说明对不上你拉下来的镜像),镜像作者将这个目录作为其数据的存储位置。
第二个-v
表示将/opt/gitProject/yjybase/mysql
绑定到容器的/etc/mysql/conf.d
中,这里看mysql5.7.44版本镜像的使用说明,放的是mysql的配置文件,我只需要将我的配置文件放在这个目录中进行调整,容器中对应的位置也会有一份相同的文件进行相同的调整,这就非常方便开发和配置,比如我开发一个html应用,绑定到对应的代码目录后,只需要将宿主机中的代码修改后,容器中的代码也同步
修改了。不然每次修改代码后就要生成一个镜像然后重新run。
1.2、多应用协同运行
以次类推你可以运行一个php镜像,然后将你的代码绑定到对应的容器目录下,启动后根据暴露的接口在浏览器中访问。其中php需要操作mysql数据库,你就可以使用之前的mysql容器,用服务器的ip和其暴露的端口进行连接,这里我以webman举例
这样运行肯定是会报错的因为运行webman还需要额外的扩展,基本上不会这样跑,需要用到Dockerfile
,这个后面说,这里只是简单介绍一下,假设webman运行只要基础的php环境,且index.php里面写好了连接mysql的代码,且调用了一个输出数据库表的内容的方法。
docker run -dp 3111:8000 \
-v /opt/gitProject/webman:/var/www/html \
--name test_webman \
-it php:8.2-fpm php start.php start
webman的数据库配置中如下
return [
// 默认数据库
'default' => 'mysql',
// 各种数据库配置
'connections' => [
'mysql' => [
'driver' => 'mysql',
'host' => '当前服务器地址',
'port' => 3306,
'database' => 'webman',
'username' => 'webman',
'password' => '',
]
]
]
当在浏览器中输入 服务器地址:3111
,正常情况下可以看到index.php的内容。以此类推,如果你还需要运行一个web(如vue打包的那种),你还可以跑一个nginx容器,将web绑定到nginx容器的指定目录中,对外暴露端口80以及对应nginx容器的80端口,然后nginx容器的配置文件中监听web端请求地址对应的转发到webman中的index去,这样就可以跑起一个简单的LNMP项目。
2、制作镜像
这里说的制作镜像是指在官方或者第三方镜像上进行修改后再生成的镜像,完成后可以发布到官方的仓库、私人仓库、或者仅存与你的描述文件(Dockerfile
)中。
首先需要一个Dockerfile
文件用来描述创建这个镜像需要哪些步骤,简单的格式如下
FROM xxx
WORKDIR xx
COPY x x
RUN xxx
CMD xxx
EXPOSE xxx
FROM
表示来自于哪个基础镜像,WORKDIR
设置工作目录,就是运行的时候容器使用那个目录做入口,COPY
表示将宿主机中指定位置的内容复制到容器中指定位置里面去,RUN
表示创建镜像到这一步需要在执行什么命令,CMD
表示这个镜像在运行一个新容器的时候运行的命令,EXPOSE
表示将容器中指定的端口暴露出来。
注意别把镜像创建和容器的创建概念弄混淆了
2.1、创建一个简单的可以运行webman的php镜像
先在webman项目根目录创建一个Dockerfile无后缀文件,写入如下
FROM php:8.2-fpm-alpine
# 设置alpine系统apk仓库源
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
# 安装依赖
RUN apk add gcc g++ autoconf make
# 安装Redis扩展
RUN pecl install igbinary lzf zstd \
&& docker-php-ext-enable igbinary lzf zstd \
&& pecl install redis \
&& docker-php-ext-enable redis
RUN docker-php-ext-install pdo pdo_mysql
RUN docker-php-ext-install pcntl
# 设置工作目录
WORKDIR /app
# 将当前目录的内容复制到容器的工作目录中
COPY . /app
# 暴露应用程序的端口
EXPOSE 8000
# 运行应用程序
CMD php start.php start
这里的意思就是在php:8.2-fpm-alpine
这个镜像的基础上,先在这个系统上把安装软件的仓库源替换为国内的镜像源(不然安装慢得你怀疑人生)然后就是安装各种插件和扩展用于可以运行webman(如果你的webman项目中用到了使用gd库生成验证码这种功能,那么你还要额外安装gd扩展,这就需要各位根据自己项目要求来确定了)。
docker-php-ext-install
这个开头的命令是值docker中针对php安装扩展的,当然你也可以使用其他的安装方式,如pecl
,只是docker-php-ext-install
安装后不需要进入php.ini中开启。
然后设置镜像中的根目录下的app目录作为工作目录,将宿主机当前目录下的所有内容都拷贝到app中去,再暴露8000端口给外面(webman默认配置是暴露8000,具体是多少你需要根据你的webman配置来确定),最后就是运行容器的时候需要执行的命令。
在当前目录下使用终端 使用 docker build -t test .
,表示创建一个test镜像,创建成功后可以使用docker run -dp 8001:8000 --name test_php test
正常情况下浏览器中输入服务器地址:8001
即可访问
3、编排
上面说的在初步使用的时候,并没有什么太大问题。但是用久了你就会发现特别繁琐,特别是开发的时候,你还要告诉开发的小伙伴输入好几个命令,而且应用之间的关联也是通过ip来关联,改来改去也麻烦。
docker-compose很好的解决了这些麻烦事,使用后只需要开发的源代码,以及一个compose.yaml文件,在此目录使用 docker compose up -d
即可运行整个项目(当然啦,对开发人员来说因为开发项目多,很容易端口冲突,该改的还是要改哈哈哈哈)。
3.1、简单示例
创建一个docker-compose.yml文件,写入如下
services:
myredis608:
image: redis:6.0.8
ports:
- 0.0.0.0:6380:6379
volumes:
- ./redis/conf/redis.conf:/usr/local/etc/redis/redis.conf
- ./redis/data:/data
command: redis-server /usr/local/etc/redis/redis.conf
且在此目录下创建redis文件夹,在里面分别创建上面代码中volumes对应的文件和文件夹。
简单解释一下上面的代码:使用redis6.0.8的镜像创建一个myredis608
的容器,对外的端口是6380。服务器监听到6380后访问这个容器的6379端口,且将宿主机的./redis/conf/redis.conf
绑定到容器的配置文件目录。将./redis/data
绑定到这个容器存放数据的目录下(这样容器删除了数据还可以在宿主机中找到),然后在容器启动的时候应用指定目录下的配置文件启动。
3.2、本人实际应用
我的这个项目是LNMP(Linux+nginx+MySQL+PHP)类型,php用的是webman的框架且自己二开,前端是vue3+vite
services:
yjyadmin_php:
build:
context: ./yjyadmin
dockerfile: Dockerfile
image: yjyadmin
ports:
- 0.0.0.0:3001:8000
working_dir: /app
volumes:
- ./yjyadmin:/app
yjyadmin_mysql5744:
image: mysql:5.7.44
container_name: diy_yjyadmin_mysql5744
ports:
- 0.0.0.0:3306:3306
volumes:
- mysql-data:/var/lib/mysql
- ./mysql:/etc/mysql/conf.d
environment:
MYSQL_ROOT_PASSWORD: 123456
# 6.0.8
yjyadmin_myredis608:
image: redis:6.0.8
ports:
- 0.0.0.0:6379:6379
volumes:
- ./redis/conf/redis.conf:/usr/local/etc/redis/redis.conf
- ./redis/data:/data
command: redis-server /usr/local/etc/redis/redis.conf
yjyadmin_web:
image: nginx:1.25.3
ports:
- 1818:80
volumes:
- ./web_dist:/usr/share/nginx/html:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./nginx/logs:/var/log/nginx
volumes:
mysql-data:
external: true
name: mysql-data
以上是我的compose.yaml内容。和之前介绍不同的是yjyadmin_php
下面有个build
,这是因为运行webman需要php环境但是还需要一些额外的扩展,比如我这里图片验证码使用的是buildadmin
项目中的,所以需要gd库。官方的镜像中没有安装这些,所以需要一个基于php的自定义镜像。build
就很容易的解决了这个问题,只需要我们告诉它去哪里找到生成镜像的描述和上下文即可
这是我的目录结构(为了更加直观,所以单独把mysql、nginx、redis这几个公用的放在了这个项目中,实际情况下这几个都是公用的,当然啦也可以每个项目开一个,还是看各位自己的要求哈哈哈哈)忽略dockerfile_command
和pull.sh
文件。
- web_dist:vue打包的内容(服务器是2核2g的丐版配置,而且我的vue项目很大,根本没法用服务器打包。各位服务器ok的话可以少个文件夹哈哈哈哈)
- yjyadmin-web:项目前端源码vue3+vite,在这里没用到
- yjyadmin:基于webman二开的后端,里面放有一个
Dockerfile
文件,用来配合上面的build
Dockerfile内容如下(切换国内源这块好像有问题,速度慢,暂时没去处理)
FROM php:8.2-fpm
# 切换国内源
RUN touch /etc/apt/sources.list.d/diy.list&&sed -i 's/deb/#deb/g' /etc/apt/sources.list.d/diy.list
RUN sed -i '$a\deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free' /etc/apt/sources.list.d/diy.list
RUN sed -i '$a\deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free' /etc/apt/sources.list.d/diy.list
RUN sed -i '$a\deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-backports main contrib non-free' /etc/apt/sources.list.d/diy.list
RUN sed -i '$a\deb https://security.debian.org/debian-security bullseye-security main contrib non-free' /etc/apt/sources.list.d/diy.list
# 更新 Debian
RUN apt update && apt -y upgrade
# 安装Redis扩展
RUN pecl install igbinary lzf zstd \
&& docker-php-ext-enable igbinary lzf zstd \
&& pecl install redis \
&& docker-php-ext-enable redis
RUN apt-get install -y \
libfreetype-dev \
libjpeg62-turbo-dev \
libpng-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd
RUN docker-php-ext-install pdo pdo_mysql
RUN docker-php-ext-install pcntl
# 设置工作目录
WORKDIR /app
# 将当前目录的内容复制到容器的工作目录中
COPY . /app
# 暴露应用程序的端口
EXPOSE 8000
# 运行应用程序
CMD php webman start
进入compose.yaml文件目录,输入命令docker compose up -d
正确的话如下
第一次会久一点,后面在此运行就很快的。
引用且使用的镜像如下
在浏览器中输入服务器地址:1818
界面显示如下
3.2、补充
上面应用之间的联系我说的都是通过服务器地址来访问,但实际上最后我使用的是docker中的别名。比如php中连接redis,mysql,我使用的是如下配置
因为相同compose中默认会创建一个network,可以互相通过别名(就是compose文件中service的名称)ping通。也可以通过 docker inspect 容器名/容器id
查看这次compose中生成的容器中的networks选项如下
其中Aliases
中会生成3个别名,第一个(如果你设置了container_name
第一个就会被替换掉)是会默认拼接你当前目录的名称,如果你使用docker compose -p 项目名称 up -d
使用了-p指令,这里就会改为拼接你的项目名称
,第二个就是service
的名称,第三个是自动生成的唯一id
3.2.1、容器互通(通过名称)
如果这个redis或者mysql是供大家一起使用的,就需要在这个容器单独运行前先创建
一个networkdocker network create test_network
,然后运行且加入
docker run --name mysql5744 -dp 3306:3306
--network test_network
-v mysql-data:/var/lib/mysql
-v /opt/gitProject/yjybase/mysql:/etc/mysql/conf.d
-e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.44
其他容器想通过docker别名联通mysql5744
就也需要使用--network test_network
。
3.2.2、compose中与其他容器互通
也是一样的在compose中配置networks
version: '3'
services:
bizapi:
image: registry.cn-hangzhou.aliyuncs.com/xxxx/docker_php73_v5:latest
ports:
- 8501:80
volumes:
- ../biz/:/www
- ../docker/yaconf:/www/docker/yaconf
- ../docker/nginx-log/:/var/log/nginx
- ../docker/php-fpm-log/:/var/log/php-fpm
- ../docker/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf
- ../docker/phpconf/conf.d/docker-php-ext-yaconf-local.ini:/usr/local/etc/php/conf.d/docker-php-ext-yaconf.ini
- ../docker/phpconf/php.ini:/usr/local/etc/php/php.ini:ro
networks:
- thinkpanax_net
- default
centerbin:
image: registry.cn-hangzhou.aliyuncs.com/xxxx/docker_php73_v5:latest
ports:
- 8503:80
volumes:
- ../gx_centerbin/:/www
networks:
thinkpanax_net:
external: true
上面是我另外一个项目的部分内容,项目名称加gx
,我的一个容器叫my_redis
是单独运行的且加入到了thinkpanax_net
网络中,其中bizapi
是作为后端处理业务,centerbin
作为前端展示用的。
上面bizapi
中有个networks
,表示加入到thinkpanax_net
和default
网络中,bizapi
中可以通过ping my_redis
和ping centerbin
ping通(首先要进入容器docker exec -it gx-bizapi-1 /bin/sh
,为什么用/bin/sh
这个需要看容器是怎么启动的,有的用bash
等等,先不解释这些)。
最下面的networks
表示这个网络是已经存在的,compose到时候不会去检查,否则的话运行不起来的。
上面需要注意的是如果bizapi
设置了networks,那么就不会加入到compose的默认的网络中,所以如果不写default
那么就无法与centerbin
联通的。如下是bizapi
中networks的描述,可以看到加入了两个网络。下图是docker desktop
客户端,请去官网下载,初学者配合基础的命令,可以直观的在这体现和调整。