楚昭男 發表於 2025-3-21 17:25:00

记录---学习项目如何用Docker部署

<h1 data-id="heading-0">🧑‍💻 写在开头</h1>
<p>点赞 + 收藏 === 学会🤣🤣🤣</p>
<h2 data-id="heading-0">写在前面</h2>
<h3 data-id="heading-1">Docker对比传统虚拟机</h3>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321171318801-1475790800.png" alt="" loading="lazy"></p>
<blockquote>
<p>&nbsp;Docker 是个划时代的开源项目,它彻底释放了计算虚拟化的威力,极大提高了应用的维护效率,降低了云计算应用开发的成本!使用 Docker,可以让应用的部署、测试和分发都变得前所未有的高效和轻松! 无论是应用开发者、运维人员、还是其他信息技术从业人员,都有必要认识和掌握 Docker,节约有限的生命。</p>
</blockquote>
<p>&nbsp;</p>
<div>
<div>
<p>文章的主旨通过让开发者通过将一个vue项目进行Docker化,以达到对Docker学习作用,主要流程如下</p>
<ul>
<li>
<p>打包手头的一个Vue项目,生成的<code>dist文件夹</code>,编写<code>Dockerfile</code>文件 通过docker打包生成一个<code>前端镜像</code>,然后通过这个<code>前端镜像</code>实例化启动一个<code>前端容器</code> 实现前端项目部署</p>
</li>
<li>
<p>配置后端环境,或者启动一个<code>node服务</code>,实现简单接口。也通过docker打包生成一个<code>node服务镜像</code>,运行一个<code>nodeserver容器</code>,提供后端接口 实现后端服务部署</p>
</li>
<li>
<p>通过<code>nginx</code>代理,让前端接口的请求转发到<code>nodeserver容器</code>上 实现<code>nginx代理转发</code></p>
</li>
</ul>
<h2 data-id="heading-2">1. Docker是什么?为什么要用?</h2>
<h3 data-id="heading-3">Docker基本概念</h3>
<p>上面说了一堆流程,最开始者要先理解docker的三个基本概念</p>
<ul>
<li><strong>镜像(Image):</strong> Docker 镜像是一个只读的模板,用来创建容器,简单来说就是为<code>容器</code>运行提供需要的程序、资源、配置等, 他在构建成功后就不会变化,只用于启动容器</li>
<li><strong>容器(Container):</strong> 容器是镜像的运行实例,可以被启动、停止、删除 ,一个Docker镜像可以例化出来多个容器,每个容器之间是独立的。Docker的容器是用来<code>运行程序的,</code>可以理解为Docker的容器就是一个操作系统,目的是运行我们写的程序。</li>
<li><strong>仓库(Repository):</strong> 用来存储和分发 Docker 镜像的地方 Dockerhub 有点类似于github用户可以在上面托管镜像</li>
</ul>
<p>核心概念就是,通过<strong>Dockerfile</strong>生成<code>镜像</code><strong>或者从Dockerhub</strong>中获取镜像 然后去创建<code>容器</code>,最后让<code>程序跑在容器上</code>。</p>
<p>理解了这三个概念,就理解了 <strong>Docker</strong> 的整个生命周期</p>
<h3 data-id="heading-4">为什么要使用Docker</h3>
<ul>
<li><strong>环境一致性:</strong> 避免发生在我的电脑上能运行,别人的电脑上用不了的问题,确保开发、测试和生产环境的一致性</li>
<li><strong>版本隔离:</strong> 在同一台服务器上运行不同版本的应用(如不同版本的Node.js),避免项目报错</li>
<li><strong>服务迁移:</strong> 容器化后的应用可以轻松地在不同服务器间迁移,无需担心环境差异</li>
<li><strong>标准化交付:</strong> 提供了一个标准的软件交付方式,减少了人为部署错误</li>
</ul>
<p>使用Docker不仅能解决传统部署中的环境依赖问题,还能大大提高开发和部署效率。如果你管理多个项目,Docker能显著简化维护工作,你总不想因为不同的环境,不同的依赖导致问题而苦恼吧.</p>
<p>对于前端开发的日常来说,基本用不到容器化, 基本的部署也是打个dist包给运维(后端)让他们部署</p>
<p><strong>前端开发不懂容器化很正常,但是至少要让自己了解它。</strong></p>
<h2 data-id="heading-5">2. 环境搭建</h2>
<h3 data-id="heading-6">Docker 安装</h3>
<p>docker 分为 <code>stable</code> <code>test</code> 和 <code>nightly</code> 三个更新频道。官方网站上有各种环境下的 安装指南,</p>
<p>根据操作系统选择安装方式:</p>
<ul>
<li>
<p>Linux 安装</p>
<div class="code-block-extension-header">
<div class="code-block-extension-headerLeft">
<div class="code-block-extension-foldBtn">
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># Ubuntu
sudo apt-get update
sudo apt-get install docker-ce

# CentOS
sudo yum install docker-ce</pre>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
<ul>
<li>
<p>Windows/Mac 安装</p>
<p>下载并安装&nbsp;Docker Desktop。</p>
</li>
</ul>
<p>安装完成后执行<code>docker --version</code>验证是否成功</p>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321171433102-1874330746.png" alt="" loading="lazy"></p>
<p>&nbsp;如果&nbsp;<code>docker version</code>、<code>docker info</code>&nbsp;都正常的话,可以尝试运行一下&nbsp;Nginx 服务器:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">docker run -d -p 80:80 --name webserver nginx`</pre>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321171500934-421041031.png" alt="" loading="lazy"></p>
<p>&nbsp;服务运行后,可以访问&nbsp;http://localhost,如果看到了 "Welcome to nginx!",就说明基础环境都配置成功了。</p>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321171516238-1991149921.png" alt="" loading="lazy"></p>
<p>&nbsp;可以通过命令行或者通过Docker Desktop停止 Nginx 服务器并删除执:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">docker stop webserver
docker rm webserver</pre>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321171545968-1595401532.png" alt="" loading="lazy"></p>
<p>&nbsp;如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以在 Docker Desktop 配置国内镜像加速。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">"registry-mirrors":[
    "https://registry.docker-cn.com",
    "https://docker.mirrors.ustc.edu.cn",
    "http://hub-mirror.c.163.com"
]</pre>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321171616217-360736254.png" alt="" loading="lazy"></p>
<div>
<div>
<h2 data-id="heading-7">3. 将项目容器化</h2>
<h3 data-id="heading-8">3.1 构建镜像前准备</h3>
<p>首先明确2个概念</p>
<ul>
<li>
<p>docker 中容器(<strong>Container</strong>)像一个虚拟机,容器中运行着一个完整的操作系统。可以在容器中装 Nodejs,mySql等,可以在命令行中执行相对应的操作</p>
</li>
<li>
<p>镜像(<strong>Image</strong>)是一个文件,它是用来创建容器的。他通过执行Dockerfile文件而来</p>
</li>
</ul>
<p>在项目根目录下建立3个文件, 分别为</p>
<ul>
<li><code>dockerfile</code> 用于配置docker构建信息</li>
</ul>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># 使用 Node.js 16 作为基础镜像
FROM node:16.14.2

# 将当前工作目录设置为/app
WORKDIR /app

# 将 package.json 和 package-lock.json 复制到 /app 目录下
COPY package*.json ./

# 运行 npm install 安装依赖
RUN yarn install


# 将源代码复制到 /app 目录下
COPY . .

# 打包构建
RUN npm run build

# 将构建后的代码复制到 nginx 镜像中
FROM nginx:latest
COPY --from=0 /app/dist /usr/share/nginx/html

# 复制自定义的Nginx配置到镜像中,覆盖默认配置
COPY nginx/default.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

# 启动 nginx 服务
CMD ["nginx", "-g", "daemon off;"]</pre>
</div>
<p>只有&nbsp;<code>RUN</code>,&nbsp;<code>COPY</code>,&nbsp;<code>ADD</code>&nbsp;会创建层数, 其它指令不会增加镜像的体积</p>
<p>如果是构建过程中npm因为网络原因,安装依赖失败可以考虑使用 npm镜像地址或者使用cnpm</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># 运行 npm install 安装cnpm 再通过cnpm安装依赖
RUN npm -g --cache=none --registry https://registry.npmmirror.com \
&amp;&amp; cnpm install</pre>
</div>
<ul>
<li><code>dockerignore</code>&nbsp;与<code>.gitignore</code>&nbsp;语法一致。使用它排除构建无关的文件及目录,如&nbsp;<code>node_modules</code></li>
</ul>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">.DS_Store
node_modules
/dist


# local env files
.env.local
.env.*.local

# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
dist.zip</pre>
</div>
<ul>
<li><code>nginx/default.conf</code>&nbsp;用于自定义配置ngnix配置</li>
</ul>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">server {
    listen 80;   # 端口号是80
    server_name localhost;
   
    location / {
      root   /usr/share/nginx/html;# nginx 默认会从这个路径下加载网页,这是 nginx 默认的网页根目录
      indexindex.html index.htm;
    }

    error_page404            /404.html;# 错误404处理
    error_page500 502 503 504/50x.html;# 错误5XX处理

    location = /50x.html {
      root   /usr/share/nginx/html;
    }
}
</pre>
</div>
<h3 data-id="heading-9">3.2 通过使用docker build命令构建前端镜像</h3>
<p>编写完成3个文件后就可以开始构建了,执行下列命令</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">docker build -t gyljr-admin:v1 .</pre>
</div>
<div>
<div>这里的<code>docker build -t</code> 后面第一个参数为我自定义的项目名,你也可以随便取一个,第二个:v1则代表构建的tag 如果通过这个来区分不同版本构建.最后的.号代表上下文路径,<code>docker</code> 会在这个路径下寻找 <code>dockerfile</code> 及其他文件,根据 <code>dockerfile</code> 配置打镜像。</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321171810664-1703595783.png" alt="" loading="lazy"></p>
<div>
<div>
<p>如果成功打出了镜像,可以在本地运行一下这个镜像进行验证</p>
<p>通过<code>docker run -d -p 3000:80 --name gyljr-admin-web gyljr-admin:v1</code> 来运行</p>
<p><code>3000:80</code>代表把宿主机的 <code>3000</code> 端口转发到容器的 <code>80</code> 端口,<code>gyljr-admin:v1</code>则是我们刚才打出的镜像的名字。</p>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321171827024-607692253.png" alt="" loading="lazy"></p>
<div>
<div>
<p>可以通过<code>docker ps</code> 或者直接访问 http://localhost:3000/ 此时应该可以看到 前端静态页面已经部署</p>
<p>这时我们发现网页的接口请求都为404,是因为我们只部署了前端的页面和静态资源还需要部署后端的接口服务</p>
<h3 data-id="heading-10">3.3 编写简易node后端服务</h3>
<p>由于我手头上没有合适的后端服务,如果有需要可以先安装docker数据库,开发环境等,因此我打算用一个简单的node服务来模拟后端服务</p>
<p>新建项目文件夹后执行</p>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">npm i koa koa-router nodemon</pre>
</div>
创建一个简单的 Koa 服务作为示例:<br>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">const Koa = require('koa');
const Router = require('koa-router');

const app = new Koa();
const router = new Router();

async function handleRequest(ctx) {
    try {
      ctx.body = {
            "code": 200,
            "status": 1,
            "message": "ok",
            "data": {
                "userRole": 1,
                "userId": "000000000000000001",
                "companyId": "1000000000000000001",
                "userName": "test",
            }
      }
    } catch(error) {
      ctx.status = 500;
      ctx.body = {
            error: 'Internal Server Error'
      };
    }
}

router.post('/Account/SignIn', async(ctx) = &gt;{
    await handleRequest(ctx);
});


// 使用路由中间件
app.use(router.routes());
app.use(router.allowedMethods());

// 启动服务器
const port = 1000;
app.listen(port, () = &gt;{
    console.log(`Server is running on port $ {
      port
    }`);
});</pre>
</div>
<div>
<div>
<p>可以看到这个node 服务主要功能就是接受一个post请求,模拟请求,接口路径是<code>http://localhost:1000/Account/SignIn</code></p>
<p>这里可以根据你项目实际情况修改,在你的前端项目的请求中,找个接口的路径名称复制上去即可, 我这里是用的登陆接口</p>
<p>修改该项目<code>pack.json</code></p>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">{
"type": "commonjs",
"scripts": {
    "start": "nodemon app.js" //主要是这行
},
"dependencies": {
    "koa": "^2.15.2",
    "koa-router": "^12.0.1"
},
"devDependencies": {
    "nodemon": "^3.1.9"
}
}</pre>
</div>
运行<code>node app.js</code>发现项目正常启动,且用<code>postman</code>或其他接口工具能够正常访问即可开始构建镜像<br>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321171938207-1906136298.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<h3 data-id="heading-11">3.3 构建node后端服务镜像</h3>
<ul>
<li>编写Dockerfile文件</li>
</ul>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># 指定镜像
FROM node:16.14.2

# 复制文件到容器中 .就是当前目录下所有的文件。 /app就是容器的路径(自定义)
ADD . /app

# 进入工作区(跟复制的文件路径一致)
WORKDIR /app

# 安装依赖
RUN npm install

# 暴露端口
EXPOSE 1000

# 启动服务
CMD ["node", "app.js"]</pre>
</div>
<h3 data-id="heading-12">3.2 Docker 配置与构建</h3>
<p>创建dockerfile 文件:这里我node服务写的比较简单只需要安装依赖即可执行,如果比较复杂的话需要修改这里配置</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># 指定基础镜像
FROM node:16.14.2

# 设置工作目录
WORKDIR /app

# 复制项目文件
ADD . /app

# 安装依赖
RUN npm install

# 暴露端口
EXPOSE 1000

# 启动服务
CMD ["node", "app.js"]</pre>
</div>
之后一样的 可以通过命令来构建镜像<br>
</div>
<div>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">docker build -t node_server:v1 .</pre>
</div>
</div>
<div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321172109543-1535139738.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321172122290-2135386684.png" alt="" loading="lazy"></p>
<p>&nbsp;可以看到我们的镜像都已经构建成功,之后执行代码来运行容器</p>
</div>
<div>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">docker run -d --name node_server_container -p 9000:1000 node_server:v1
</pre>
</div>
<p>  </p>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321172147606-1703413590.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<h2 data-id="heading-13">4 Nginx 反向代理配置</h2>
</div>
<div>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"> proxy: {
      '/api': {
          target: `http://xxx.xx.x.x:xxxx`, // 后端地址服务地址
          changeOrigin: true,
          secure: false,
          rewrite: (path) =&gt; path.replace(/^\/api/, ''),
      },
      }
</pre>
</div>
<p>  </p>
<div>
<div>
<p>我们平常开发前端的项目时,如果请求本地的后端地址,实际上是<code>vite</code>或者<code>webpack</code>都会启动一个服务用于转发我们的接口路径,从而达到解决跨域问题的效果,但是现在打包后前端项目都是静态而且位于docker容器内该如何转发呢?</p>
<p>接下来我们就需要将前端页面的请求通过<code>nginx</code>转发到<code>node_server_container这</code>个容器的ip和端口下</p>
<h3 data-id="heading-14">4.1 Docker容器ip,端口获取</h3>
<p>可以通过<code>docker desktop</code>查看一下<code>node_server_container</code>的ip 命令行可以通过先用<code>docker ps</code> 获取容器id后 <code>docker inspect 容器id</code> 获取ip</p>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321172220342-1351993079.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<h3 data-id="heading-15">4.2 修改ngnix配置</h3>
<p>知道了node服务端的ip和端口接下来只要修改nginx配置即可,这时候可以不用重新打镜像而是直接修改镜像的ngnix配置</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">server {
    listen 80;   # 端口号是80
    server_name localhost;
   
    location / {
      root   /usr/share/nginx/html;# nginx 默认会从这个路径下加载网页,这是 nginx 默认的网页根目录
      indexindex.html index.htm;
    }
          location /api/ {   
      rewrite/api/(.*)/$1break;# 如果需要把路径/api路径替换为/像我这个后端服务中没有需要替换的路径这里其实用不到
      proxy_pass http://172.17.0.3:1000;
          }

    location /Account/ {
      proxy_pass http://172.17.0.3:1000;# proxy_pass:就是对应代理到server容器上的地址。
    }

    error_page404            /404.html;# 错误404处理
    error_page500 502 503 504/50x.html;# 错误5XX处理

    location = /50x.html {
      root   /usr/share/nginx/html;
    }
}</pre>
</div>
<br>
</div>
</div>
<div>修改容器ngnix配置可以通过以下方法</div>
<div>&nbsp;</div>
<div>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">docker exec -it gyljr-admin-web bash
</pre>
</div>
<p>  </p>
</div>
<div>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># 修改配置文件
vi /etc/nginx/conf.d/default.conf</pre>
</div>
</div>
<div>&nbsp;</div>
<div>用vi修改完成后,按<code>ESC</code>&nbsp;键 跳到命令模式,然后输入退出命令<code>:wq</code>&nbsp;即可保存文件并退出vi,之后执行</div>
<div>&nbsp;</div>
<div>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># 测试配置是否正确
nginx -t

# 重载配置(不停止服务)
nginx -s reload
</pre>
</div>
<p>  </p>
</div>
<div>
<p>如果你docker内没有vi 那就先安装一个或者直接改前端项目的<code>nginx/default.conf</code>配置,之后再重新打包一个镜像即可,下面是容器内安装vi的方法</p>
<p>查看版本</p>
</div>
<div>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">cat /etc/os-release
</pre>
</div>
<p>  </p>
</div>
<div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321172402274-192345408.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># Debian/Ubuntu based

apt-get update
apt-get install vim

# Alpine based

apk add --no-cache vim
</pre>
</div>
<p>  </p>
</div>
<div>如此完成<code>ngnix</code>配置的修改后再次登陆前端页面可以发现,页面已经可以正常请求</div>
<div>&nbsp;</div>
<div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202503/2149129-20250321172425768-1422534854.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<div>
<div>
<h3 data-id="heading-16">4.3 常用 Docker 命令速查</h3>
<ul>
<li>
<p>构建镜像:docker&nbsp;build -t &lt;镜像名&gt; .</p>
</li>
<li>
<p>运行容器:docker run -p &lt;本地端口&gt;:&lt;容器端口&gt; -d &lt;镜像名&gt;</p>
</li>
<li>
<p>查看正在运行的容器:docker&nbsp;ps</p>
</li>
<li>
<p>停止容器:docker&nbsp;stop&nbsp;&lt;容器ID&gt;</p>
</li>
<li>
<p>删除容器:docker rm &lt;容器ID&gt;</p>
</li>
<li>
<p>查看镜像列表:docker images</p>
</li>
<li>
<p>删除镜像:docker rmi&nbsp;&lt;镜像ID&gt;</p>
</li>
<li>
<p>查看容器日志:docker logs&nbsp;&lt;容器ID&gt;</p>
</li>
<li>
<p>进入容器内部:docker&nbsp;exec -it &lt;容器ID&gt; /bin/bash</p>
</li>
<li>
<p>查看容器内部文件:docker exec -it&nbsp;&lt;容器ID&gt; ls</p>
</li>
</ul>
<h2 data-id="heading-17">后记</h2>
<p>在本项目中学习 docker 的使用,还学会了如何使用 docker 制作镜像、运行容器, 其实还可以做自动化CI/CD 配置,从而实现代码提交或者更新 自动化构建然后发布,这个可以留个坑后续再做分享。</p>
<p>最后的最后,本着年底总得折腾点啥的心思写了这篇文章,如果有错误或者不足希望各位指正</p>
</div>
<div>
<h2>本文转载于:https://juejin.cn/post/7454451635407945739</h2>
</div>
<h3 id="tid-D8HBxE">如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。</h3>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202501/2149129-20250122165814748-630765389.png" alt="" loading="lazy"></p>
</div>
</div>
</div>
</div><br><br>
来源:https://www.cnblogs.com/smileZAZ/p/18785488
頁: [1]
查看完整版本: 记录---学习项目如何用Docker部署