heroku docker bundle not found error // 我正在尝试将 dockerfile 部署到 heroku 但它总是说我 bundle not found
heroku docker bundle not found error // i'm trying to deploy dockerfile to heroku but it always says me bundle not found
我正在尝试 运行 docker 在 heroku 上
所以我试过了
“git 添加 heroku.yml”
"git commit m "添加 yml"
“git heroku push”
但是正如您在这里看到的,heroku 日志向我显示了这个日志
2022-01-24T04:10:12.979291+00:00 heroku[web.1]: Restarting
2022-01-24T04:10:15.729676+00:00 app[api]: Remove PATH config vars by user hanjk13262@gmail.com
2022-01-24T04:10:15.729676+00:00 app[api]: Release v37 created by user hanjk13262@gmail.com
2022-01-24T04:10:15.965096+00:00 heroku[web.1]: Restarting
2022-01-24T04:10:21.029250+00:00 heroku[web.1]: Starting process with command `/bin/sh -c bundle\ exec\ puma\ -C\ config/puma.rb`
2022-01-24T04:10:22.051845+00:00 app[web.1]: /bin/sh: 1: bundle: not found
2022-01-24T04:10:22.172593+00:00 heroku[web.1]: Process exited with status 127
2022-01-24T04:10:39.006056+00:00 heroku[web.1]: Starting process with command `/bin/sh -c bundle\ exec\ puma\ -C\ config/puma.rb`
2022-01-24T04:10:40.617158+00:00 app[web.1]: /bin/sh: 1: bundle: not found
2022-01-24T04:10:40.794603+00:00 heroku[web.1]: Process exited with status 127
2022-01-24T04:10:40.946303+00:00 heroku[web.1]: State changed from starting to crashed
2022-01-24T04:10:41.842541+00:00 heroku[web.1]: Starting process with command `/bin/sh -c bundle\ exec\ puma\ -C\ config/puma.rb`
2022-01-24T04:10:43.098998+00:00 app[web.1]: /bin/sh: 1: bundle: not found
2022-01-24T04:10:43.326072+00:00 heroku[web.1]: Process exited with status 127
2022-01-24T04:11:41.000000+00:00 app[api]: Build started by user hanjk13262@gmail.com
2022-01-24T04:14:11.000000+00:00 app[api]: Build succeeded
2022-01-24T04:14:11.299638+00:00 app[api]: Release v38 created by user hanjk13262@gmail.com
2022-01-24T04:14:12.170626+00:00 heroku[web.1]: State changed from crashed to starting
2022-01-24T04:14:31.949298+00:00 heroku[web.1]: Starting process with command `/bin/sh -c /bin/sh\ -c\ bundle\\ exec\\ puma\\ -C\\ config/puma.rb`
2022-01-24T04:14:32.978306+00:00 app[web.1]: /bin/sh: 1: bundle: not found
2022-01-24T04:14:33.120489+00:00 heroku[web.1]: Process exited with status 127
2022-01-24T04:14:33.222836+00:00 heroku[web.1]: State changed from starting to crashed
我不知道它有什么问题因为这个 docker 文件正在本地工作
但是当我 运行 它在 heroku 中时,总是向我显示此日志
所以它完全吓坏了我
我的 Dockerfile
FROM node:14.17.5
RUN apt-get update && \
apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \
ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget \
xvfb x11vnc x11-xkb-utils xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic x11-apps
WORKDIR /app
COPY package.json /app
RUN npm install
COPY . /app
EXPOSE 3001
CMD xvfb-run --server-args="-screen 0 1024x768x24" npm start
# FROM node:14.17.5
# RUN apt-get update && \
# apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
# libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
# libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
# libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \
# ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget \
# xvfb x11vnc x11-xkb-utils xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic x11-apps
# WORKDIR /app
# COPY package.json /app
# RUN npm install
# COPY . /app
# EXPOSE 8081
# CMD xvfb-run --server-args="-screen 0 1024x768x24" npm start
我的服务器文件 express.js
import express from "express";
import puppeteer from "puppeteer";
import cors from "cors";
import dotenv from "dotenv";
dotenv.config();
const app = express();
const whitelist = [
"http://localhost:3000",
"my netlify address",
];
const corsOptions = {
origin: (origin, callback) => {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error("Not Allowed Origin!"));
}
},
methods: ["GET", "POST", "PUT", "DELETE"],
credentials: true,
};
app.use(cors());
app.use(express.json());
// 아 맞아 전체 url갖고있으면 굳이 서버 없어도 되잖아
// 그리고 자기 아이디 작성하게 하기
const setIdPw = async (page) => {
// FIXME: 아이디 비밀번호 입력
await page.waitForSelector("input[name=userid]");
await page.waitForSelector("input[name=password]");
await page.$eval("input[name=userid]", (el) => (el.value = "userid"));
await page.$eval("input[name=password]", (el) => (el.value = "userpassword"));
await page.click('input[type="submit"]');
};
const getText = async (page) => {
// FIXME: 텍스트 크롤링
await page.waitForSelector(".article p.large");
const text = await page.evaluate(() => {
const anchor = document.querySelector(".article p.large");
return anchor.innerHTML;
});
return text;
};
const getImg = async (page) => {
try {
await page.waitForSelector(".article .attach img", { timeout: 2000 });
try {
const img = await page.evaluate(() => {
const imgsrc = document
.querySelector(".article .attach img")
.getAttribute("src");
return imgsrc;
});
return img;
} catch (error) {}
} catch (error) {
return "꽝";
}
};
const getProfile = async (page) => {
await page.waitForSelector(".picture.large");
await page.waitForSelector(".profile .large");
const profile = await page.evaluate(() => {
const Pimg = document.querySelector(".picture.large").getAttribute("src");
const username = document.querySelectorAll(".profile .large")[0].innerText;
const date = document.querySelectorAll(".profile .large")[1].innerText;
const url = window.location.href;
return { Pimg, username, date, url };
});
return profile;
};
// FIXME: 검색
app.post("/gotoEta", (req, res) => {
const { url } = req.body;
(async () => {
const options = {
args: [
"--fast-start",
"--disable-web-security",
"--disable-features=IsolateOrigins",
"--disable-site-isolation-trials",
"--disable-extensions",
"--disable-setuid-sandbox",
"--no-sandbox",
],
ignoreHTTPSErrors: true,
headless: false,
ignoreDefaultArgs: ["--disable-extensions"],
};
try {
// FIXME: 초기설정
const browser = await puppeteer.launch(options);
const page = await browser.newPage();
await page.setViewport({ width: 640, height: 768 });
const everytimeUrl = url;
await page.goto(everytimeUrl, [
"load",
"domcontentloaded",
"networkidle0",
]);
setIdPw(page);
// FIXME: 텍스트 / 사진 크롤링
const text = await getText(page);
const img = await getImg(page);
const profile = await getProfile(page);
console.log(profile);
res.json({ text, img, profile });
// FIXME: 브라우져 닫기
await browser.close();
} catch (error) {
console.log("Error " + error.toString());
res.send("오류발생1");
}
})();
});
const gotoNextPage = async (page) => {
try {
await page.waitForSelector("a.next");
await page.click("a.next");
return true;
} catch (err) {
return false;
}
};
const get20Urls = async (page) => {
await page.waitForSelector("#container .wrap.articles article a");
const urlList = await page.evaluate(() => {
const hrefs = document.querySelectorAll(
"#container .wrap.articles article a"
);
let list = [];
hrefs.forEach((val) => {
const href = val.getAttribute("href");
const url = `https://everytime.kr${href}`;
list.push(url);
});
return list;
});
// console.log(urlList);
return urlList;
};
app.get("/getEveryUrls", (req, res) => {
(async () => {
try {
const browser = await puppeteer.launch({
headless: false,
});
const page = await browser.newPage();
await page.setViewport({ width: 640, height: 500 });
const everytimeUrl = `https://everytime.kr/409275/p/1`;
await page.goto(everytimeUrl, [
"load",
"domcontentloaded",
"networkidle0",
]);
setIdPw(page);
let totalUrls = [];
let stopWhile = true;
let i = 0;
while (true) {
try {
const urls = await get20Urls(page);
totalUrls.push(...urls);
stopWhile = await gotoNextPage(page);
i += 1;
console.log(i);
} catch (error) {
break;
}
}
res.json(totalUrls);
console.log(totalUrls);
} catch (err) {
console.log("Error " + error.toString());
console.log("오류발생");
res.send("오류발생");
}
})();
});
app.get("/hi", (req, res) => {
console.log("hi there");
res.send("안녕 반가워");
});
// FIXME: 헤드레스로 만들기
const setIdPwV2 = async (page) => {
// FIXME: 아이디 비밀번호 입력
page.waitForNavigation({ waitUntil: "load" });
// await page.focus("input[name=userid]");
// await page.keyboard.type("hanjk123");
await page.$eval("input[name=userid]", (el) => (el.value = "hanjk123"));
await page.$eval("input[name=password]", (el) => (el.value = "agdsffaith00"));
page.click('input[type="submit"]');
};
const getTextV2 = async (page) => {
// FIXME: 텍스트 크롤링
await page.waitForSelector(".article p.large");
const text = await page.evaluate(() => {
const anchor = document.querySelector(".article p.large");
return anchor.innerHTML;
});
return text;
};
app.get("/gotoEtaV2", (req, res) => {
const url = "https://everytime.kr/409275/v/227352083";
(async () => {
const options = {
args: [
"--fast-start",
"--disable-web-security",
"--disable-features=IsolateOrigins",
"--disable-site-isolation-trials",
"--disable-extensions",
"--disable-setuid-sandbox",
"--no-sandbox",
],
ignoreHTTPSErrors: true,
headless: false,
ignoreDefaultArgs: ["--disable-extensions"],
};
try {
// FIXME: 초기설정
const browser = await puppeteer.launch(options);
const page = await browser.newPage();
const everytimeUrl = url;
await page.goto(everytimeUrl, [
"load",
"domcontentloaded",
"networkidle0",
]);
setIdPwV2(page);
// FIXME: 텍스트 / 사진 크롤링
const text = await getTextV2(page);
console.log(text);
// const img = await getImg(page);
// const profile = await getProfile(page);
// console.log(profile);
res.json({ text });
// FIXME: 브라우져 닫기
await browser.close();
} catch (error) {
console.log("Error " + error.toString());
res.send("오류발생1");
}
})();
});
app.listen(process.env.PORT || 3001, () => {
console.log("SERVER RUNNING ON PORT 3001");
});
pakage.json
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^14.2.0",
"express": "^4.17.2",
"nodemon": "^2.0.15",
"puppeteer": "^13.0.1"
},
"type": "module"
}
heroku.yml
build:
docker:
web: Dockerfile
run:
web: bundle exec puma -C config/puma.rb
# web: /bin/sh -c bundle\ exec\ puma\ -C\ config/puma.rb
您似乎复制了 the sample config.yml
from Heroku's documentation 但没有为 Node.js 修改它。
The run
section tells Heroku how to run your application 通过定义进程类型(例如 web
)和命令 运行 为每一个。不要使用可能适合 Rails 应用程序的 bundle exec puma
,而是输入您用来启动生产应用程序的任何命令。
根据您的 package.json
,这样的内容更合适:
run:
web: node index.js
我已经用这种部署方式解决了这个问题
heroku login
heroku container:login
docker build -t registry.heroku.com/yourHerokuAppName/web .
docker push registry.heroku.com/ollunch2/web
heroku container:release web -a ollunch2
只需将这些命令输入您的 vscode 终端
我正在尝试 运行 docker 在 heroku 上 所以我试过了 “git 添加 heroku.yml” "git commit m "添加 yml" “git heroku push”
但是正如您在这里看到的,heroku 日志向我显示了这个日志
2022-01-24T04:10:12.979291+00:00 heroku[web.1]: Restarting
2022-01-24T04:10:15.729676+00:00 app[api]: Remove PATH config vars by user hanjk13262@gmail.com
2022-01-24T04:10:15.729676+00:00 app[api]: Release v37 created by user hanjk13262@gmail.com
2022-01-24T04:10:15.965096+00:00 heroku[web.1]: Restarting
2022-01-24T04:10:21.029250+00:00 heroku[web.1]: Starting process with command `/bin/sh -c bundle\ exec\ puma\ -C\ config/puma.rb`
2022-01-24T04:10:22.051845+00:00 app[web.1]: /bin/sh: 1: bundle: not found
2022-01-24T04:10:22.172593+00:00 heroku[web.1]: Process exited with status 127
2022-01-24T04:10:39.006056+00:00 heroku[web.1]: Starting process with command `/bin/sh -c bundle\ exec\ puma\ -C\ config/puma.rb`
2022-01-24T04:10:40.617158+00:00 app[web.1]: /bin/sh: 1: bundle: not found
2022-01-24T04:10:40.794603+00:00 heroku[web.1]: Process exited with status 127
2022-01-24T04:10:40.946303+00:00 heroku[web.1]: State changed from starting to crashed
2022-01-24T04:10:41.842541+00:00 heroku[web.1]: Starting process with command `/bin/sh -c bundle\ exec\ puma\ -C\ config/puma.rb`
2022-01-24T04:10:43.098998+00:00 app[web.1]: /bin/sh: 1: bundle: not found
2022-01-24T04:10:43.326072+00:00 heroku[web.1]: Process exited with status 127
2022-01-24T04:11:41.000000+00:00 app[api]: Build started by user hanjk13262@gmail.com
2022-01-24T04:14:11.000000+00:00 app[api]: Build succeeded
2022-01-24T04:14:11.299638+00:00 app[api]: Release v38 created by user hanjk13262@gmail.com
2022-01-24T04:14:12.170626+00:00 heroku[web.1]: State changed from crashed to starting
2022-01-24T04:14:31.949298+00:00 heroku[web.1]: Starting process with command `/bin/sh -c /bin/sh\ -c\ bundle\\ exec\\ puma\\ -C\\ config/puma.rb`
2022-01-24T04:14:32.978306+00:00 app[web.1]: /bin/sh: 1: bundle: not found
2022-01-24T04:14:33.120489+00:00 heroku[web.1]: Process exited with status 127
2022-01-24T04:14:33.222836+00:00 heroku[web.1]: State changed from starting to crashed
我不知道它有什么问题因为这个 docker 文件正在本地工作 但是当我 运行 它在 heroku 中时,总是向我显示此日志 所以它完全吓坏了我
我的 Dockerfile
FROM node:14.17.5
RUN apt-get update && \
apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \
ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget \
xvfb x11vnc x11-xkb-utils xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic x11-apps
WORKDIR /app
COPY package.json /app
RUN npm install
COPY . /app
EXPOSE 3001
CMD xvfb-run --server-args="-screen 0 1024x768x24" npm start
# FROM node:14.17.5
# RUN apt-get update && \
# apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
# libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
# libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
# libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \
# ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget \
# xvfb x11vnc x11-xkb-utils xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic x11-apps
# WORKDIR /app
# COPY package.json /app
# RUN npm install
# COPY . /app
# EXPOSE 8081
# CMD xvfb-run --server-args="-screen 0 1024x768x24" npm start
我的服务器文件
import express from "express";
import puppeteer from "puppeteer";
import cors from "cors";
import dotenv from "dotenv";
dotenv.config();
const app = express();
const whitelist = [
"http://localhost:3000",
"my netlify address",
];
const corsOptions = {
origin: (origin, callback) => {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error("Not Allowed Origin!"));
}
},
methods: ["GET", "POST", "PUT", "DELETE"],
credentials: true,
};
app.use(cors());
app.use(express.json());
// 아 맞아 전체 url갖고있으면 굳이 서버 없어도 되잖아
// 그리고 자기 아이디 작성하게 하기
const setIdPw = async (page) => {
// FIXME: 아이디 비밀번호 입력
await page.waitForSelector("input[name=userid]");
await page.waitForSelector("input[name=password]");
await page.$eval("input[name=userid]", (el) => (el.value = "userid"));
await page.$eval("input[name=password]", (el) => (el.value = "userpassword"));
await page.click('input[type="submit"]');
};
const getText = async (page) => {
// FIXME: 텍스트 크롤링
await page.waitForSelector(".article p.large");
const text = await page.evaluate(() => {
const anchor = document.querySelector(".article p.large");
return anchor.innerHTML;
});
return text;
};
const getImg = async (page) => {
try {
await page.waitForSelector(".article .attach img", { timeout: 2000 });
try {
const img = await page.evaluate(() => {
const imgsrc = document
.querySelector(".article .attach img")
.getAttribute("src");
return imgsrc;
});
return img;
} catch (error) {}
} catch (error) {
return "꽝";
}
};
const getProfile = async (page) => {
await page.waitForSelector(".picture.large");
await page.waitForSelector(".profile .large");
const profile = await page.evaluate(() => {
const Pimg = document.querySelector(".picture.large").getAttribute("src");
const username = document.querySelectorAll(".profile .large")[0].innerText;
const date = document.querySelectorAll(".profile .large")[1].innerText;
const url = window.location.href;
return { Pimg, username, date, url };
});
return profile;
};
// FIXME: 검색
app.post("/gotoEta", (req, res) => {
const { url } = req.body;
(async () => {
const options = {
args: [
"--fast-start",
"--disable-web-security",
"--disable-features=IsolateOrigins",
"--disable-site-isolation-trials",
"--disable-extensions",
"--disable-setuid-sandbox",
"--no-sandbox",
],
ignoreHTTPSErrors: true,
headless: false,
ignoreDefaultArgs: ["--disable-extensions"],
};
try {
// FIXME: 초기설정
const browser = await puppeteer.launch(options);
const page = await browser.newPage();
await page.setViewport({ width: 640, height: 768 });
const everytimeUrl = url;
await page.goto(everytimeUrl, [
"load",
"domcontentloaded",
"networkidle0",
]);
setIdPw(page);
// FIXME: 텍스트 / 사진 크롤링
const text = await getText(page);
const img = await getImg(page);
const profile = await getProfile(page);
console.log(profile);
res.json({ text, img, profile });
// FIXME: 브라우져 닫기
await browser.close();
} catch (error) {
console.log("Error " + error.toString());
res.send("오류발생1");
}
})();
});
const gotoNextPage = async (page) => {
try {
await page.waitForSelector("a.next");
await page.click("a.next");
return true;
} catch (err) {
return false;
}
};
const get20Urls = async (page) => {
await page.waitForSelector("#container .wrap.articles article a");
const urlList = await page.evaluate(() => {
const hrefs = document.querySelectorAll(
"#container .wrap.articles article a"
);
let list = [];
hrefs.forEach((val) => {
const href = val.getAttribute("href");
const url = `https://everytime.kr${href}`;
list.push(url);
});
return list;
});
// console.log(urlList);
return urlList;
};
app.get("/getEveryUrls", (req, res) => {
(async () => {
try {
const browser = await puppeteer.launch({
headless: false,
});
const page = await browser.newPage();
await page.setViewport({ width: 640, height: 500 });
const everytimeUrl = `https://everytime.kr/409275/p/1`;
await page.goto(everytimeUrl, [
"load",
"domcontentloaded",
"networkidle0",
]);
setIdPw(page);
let totalUrls = [];
let stopWhile = true;
let i = 0;
while (true) {
try {
const urls = await get20Urls(page);
totalUrls.push(...urls);
stopWhile = await gotoNextPage(page);
i += 1;
console.log(i);
} catch (error) {
break;
}
}
res.json(totalUrls);
console.log(totalUrls);
} catch (err) {
console.log("Error " + error.toString());
console.log("오류발생");
res.send("오류발생");
}
})();
});
app.get("/hi", (req, res) => {
console.log("hi there");
res.send("안녕 반가워");
});
// FIXME: 헤드레스로 만들기
const setIdPwV2 = async (page) => {
// FIXME: 아이디 비밀번호 입력
page.waitForNavigation({ waitUntil: "load" });
// await page.focus("input[name=userid]");
// await page.keyboard.type("hanjk123");
await page.$eval("input[name=userid]", (el) => (el.value = "hanjk123"));
await page.$eval("input[name=password]", (el) => (el.value = "agdsffaith00"));
page.click('input[type="submit"]');
};
const getTextV2 = async (page) => {
// FIXME: 텍스트 크롤링
await page.waitForSelector(".article p.large");
const text = await page.evaluate(() => {
const anchor = document.querySelector(".article p.large");
return anchor.innerHTML;
});
return text;
};
app.get("/gotoEtaV2", (req, res) => {
const url = "https://everytime.kr/409275/v/227352083";
(async () => {
const options = {
args: [
"--fast-start",
"--disable-web-security",
"--disable-features=IsolateOrigins",
"--disable-site-isolation-trials",
"--disable-extensions",
"--disable-setuid-sandbox",
"--no-sandbox",
],
ignoreHTTPSErrors: true,
headless: false,
ignoreDefaultArgs: ["--disable-extensions"],
};
try {
// FIXME: 초기설정
const browser = await puppeteer.launch(options);
const page = await browser.newPage();
const everytimeUrl = url;
await page.goto(everytimeUrl, [
"load",
"domcontentloaded",
"networkidle0",
]);
setIdPwV2(page);
// FIXME: 텍스트 / 사진 크롤링
const text = await getTextV2(page);
console.log(text);
// const img = await getImg(page);
// const profile = await getProfile(page);
// console.log(profile);
res.json({ text });
// FIXME: 브라우져 닫기
await browser.close();
} catch (error) {
console.log("Error " + error.toString());
res.send("오류발생1");
}
})();
});
app.listen(process.env.PORT || 3001, () => {
console.log("SERVER RUNNING ON PORT 3001");
});
pakage.json
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^14.2.0",
"express": "^4.17.2",
"nodemon": "^2.0.15",
"puppeteer": "^13.0.1"
},
"type": "module"
}
heroku.yml
build:
docker:
web: Dockerfile
run:
web: bundle exec puma -C config/puma.rb
# web: /bin/sh -c bundle\ exec\ puma\ -C\ config/puma.rb
您似乎复制了 the sample config.yml
from Heroku's documentation 但没有为 Node.js 修改它。
The run
section tells Heroku how to run your application 通过定义进程类型(例如 web
)和命令 运行 为每一个。不要使用可能适合 Rails 应用程序的 bundle exec puma
,而是输入您用来启动生产应用程序的任何命令。
根据您的 package.json
,这样的内容更合适:
run:
web: node index.js
我已经用这种部署方式解决了这个问题
heroku login
heroku container:login
docker build -t registry.heroku.com/yourHerokuAppName/web .
docker push registry.heroku.com/ollunch2/web
heroku container:release web -a ollunch2
只需将这些命令输入您的 vscode 终端