Docker极简入门:使用Docker-Compose 运行网站浏览量统计Demo
Docker-Compose 是一个可以对 Docker 容器集群的快速编排的工具,能够减轻您心智和手指的负担。
简单的来说 Docker-Compose 就是将你运行多个容器的命令编写到了一起,类似于你会为一系列重复操作写一个 doSomething.sh 文件,只不过 Docker-Compose 提供了更简便的语法。
当然如果想管理多主机多容器还是推荐使用 k8s。
我们的 demo 是一个基于 node.js 的网站服务,当用户访问当前服务器的根目录时,将 redis 中的浏览量计数增加1。
先不看具体的业务代码,这其实无关紧要。假设我们已经写好了 node 服务,那么我们下一步就是写一个Dockerfile文件去构建镜像,然后执行 docker run 命令,这样整个服务就启动了。
FROM node:18-alpine
WORKDIR '/app'
COPY package.json .
RUN npm install
COPY . .
CMD ["npm","start"]
这个Dockerfile 做的事情就是
- 在容器中创建一个 app 目录,并切换到该目录。
- 将宿主机当前目录下的 package.json 文件拷贝到容器中的当前目录(/app)下
- 执行命令
npm install - 将宿主机当前目录下的所有文件拷贝到容器中(因为主体程序index.js还没有拷贝到容器中)
- 运行命令
npm start启动服务
因为我们的 node 服务用到了 redis,所以我们还需要启动一个 redis 容器。
但 docker 的机制使得这两个容器是互相隔离的,所以想要通信的话
- 将 redis 端口与宿主机端口做映射,通过宿主机的端口访问 redis
- 创建 docker network,将两个容器放在同一个 docker network下
- 编写 docker-compose.yml 文件,让Docker-Compose帮我们创建 docker network 搞定一切

docker-compose.yml
version: '3'
services:
## 容器名
redis-server:
## 指定镜像
image: 'redis:6.0.16-alpine'
## 容器重启策略
restart: 'always'
## 容器名
node-app:
## 当前目录执行 docker build
build: .
## 端口映射
ports:
- "8888:8081"
虽然我们在文件中没有写任何有关 network 的代码,但 Docker-Compose会自动帮我们创建一个network
运行命令
sudo docker-compose up --build ## 会执行yaml文件中的build命令
访问 localhost:8888 你应该能看到类似这样的界面

docker-compose 的命令跟 docker类似
docker-compose up -d ## 后台运行
docker-compose down ## 停止
最后是文件目录结构和 index.js 以及 package.json的具体代码
.
├── docker-compose.yml
├── Dockerfile
├── index.js
├── package.json
package.json
{
"dependencies": {
"express": "^4.17.3",
"redis": "^4.0.6"
},
"scripts": {
"start": "node index.js"
}
}
index.js
const express = require('express');
const redis = require('redis');
const app = express();
const client = redis.createClient({
url : 'redis://redis-server:6379' // redis-server会被docker解析并转发
});
const db = {
async set(key,value){
return fun(async()=>{
return await client.set(key,value)
},key,value)
},
async get(key){
return fun(async()=>{
return await client.get(key)
},key)
}
}
async function fun(callback,key,value){
return new Promise(async (res,rej)=>{
await client.connect();
let ok = callback(key,value);
await client.quit();
res(ok);
})
}
db.set("visits",0);
async function cntVisits(){
let cnt = await db.get("visits");
await db.set("visits",parseInt(cnt)+1);
return parseInt(cnt)+1;
}
app.get('/', (req, res) => {
cntVisits().then( result => {
res.send('Number of visits is ' + result);
});
});
// 8081是容器内部的端口,我们需要访问的是8888,因为在docker-compose.yml文件中已经做过端口映射了
app.listen(8081, () => { console.log('Listening on port 8081'); });
Docker极简入门:使用Docker-Compose 运行网站浏览量统计Demo的更多相关文章
- .Net Core in Docker极简入门(下篇)
Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 Docker-Compose 代码修改 yml file up & down 镜像仓库 最后 前言 上一篇[. ...
- Docker极简入门:使用Docker运行Java程序
运行简单的Java程序 先在当前目录创建App.java文件 public class App{ public static void main(String[] args){ String os = ...
- 小白的docker极简入门(二)、5分钟教你玩转docker安装
0-前言 上一篇中,我们已经安装后Linux了,我们需要在Linux下安装docker,然后才能在docker中安装和部署各种应用 同样,5分钟教你完成docker正确安装和使用, 不是纸上谈兵,不是 ...
- .Net Core in Docker极简入门(上篇)
目录 前言 开始 环境准备 Docker基础概念 Docker基础命令 Docker命令实践 构建Docker镜像 Dockerfile bulid & run 前言 Docker 是一个开源 ...
- Docker极简入门:使用Docker-Compose 搭建redis集群
为了构建一个集群,我们首先要让 redis 启用集群模式 一个简单的配置文件如下redis.conf # redis.conf file port 6379 cluster-enabled yes c ...
- Spring Security极简入门三部曲(上篇)
目录 Spring Security极简入门三部曲(上篇) 写在前面 为什么要用Spring Security 数据库设计 demo时刻 核心代码讲解 小结 Spring Security极简入门三部 ...
- Git 极简入门教程学习笔记
Git 极简入门教程 http://rogerdudler.github.io/git-guide/index.zh.html 测试用 https://github.com/xxx/BrnShop. ...
- ElasticSearch极简入门总结
一,目录 安装es 项目添加maven依赖 es客户端组件注入到spring容器中 es与mysql表结构对比 索引的删除创建 文档的crud es能快速搜索的核心-倒排索引 基于倒排索引的精确搜索. ...
- Spring Security极简入门三部曲(中篇)
目录 Spring Security极简入门三部曲(中篇) 验证流程 Authentication接口 过滤器链 AuthenticationProvider接口: demo时刻 代码讲解 小结 Sp ...
随机推荐
- MySQL—分页查询
分页查询 应用场景:当要显示的数据,当一页显示不全,有很多的数据时,就需要分页提交sql请求 语法:select 查询列表 from表名 [ join type join 表2 on连接条件 whe ...
- hdu5197 DZY Loves Orzing(FFT+分治)
hdu5197 DZY Loves Orzing(FFT+分治) hdu 题目描述:一个n*n的矩阵里填入1~n^2的数,要求每一排从前往后能看到a[i]个数(类似于身高阻挡视线那种),求方案数. 思 ...
- 安卓开发学习-app结构学习
开发软件:Android Studio 全局分析 gradle与idea是AS自动生成的文件 buid是编译时生成的文件 gradle里面包含gradle wrapper配置文件 gitignore是 ...
- Spring cache源码分析
Spring cache是一个缓存API层,封装了对多种缓存的通用操作,可以借助注解方便地为程序添加缓存功能. 常见的注解有@Cacheable.@CachePut.@CacheEvict,有没有想过 ...
- 生产出现oom问题,怎么排查?
生产出现oom问题,怎么排查? 1.使用dmesg命令查看系统日志 dmesg |grep -E 'kill|oom|out of memory',可以查看操作系统启动后的系统日志,这里就是查看跟 ...
- char型变量中能不能存储一个中文字符?为什么?
char型变量是用来存储Unicode编码的字符的,Unicode编码字符集中包含了汉字,因此char型变量中可以存储汉字.不过,如果某个特殊的汉字没有被包含在Unicode编码字符集中,那么,这个c ...
- Statement 和 PreparedStatement 有什么区别?哪个性 能更好?
与 Statement 相比,①PreparedStatement 接口代表预编译的语句,它主要的优 势在于可以减少 SQL 的编译错误并增加 SQL 的安全性(减少 SQL 注射攻击的可 能性):② ...
- java对象的克隆以及深拷贝与浅拷贝
一.为什么要使用克隆 在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也 ...
- java中的generate
流generate(Supplier s)返回无限顺序无序流,其中每个元素由提供的供应商生成.这适用于生成恒定流,随机元素流等. public class Flow { public static v ...
- SQL数据库之“TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2)”
一.介绍 样本:TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2) 解析:TIMESTAMPDIFF(格式,开始时间,结束时间) 二.参数解析 格式: ...