为了运行ASP.NET Core应用程序,我生成了一个dockerfile,它构建了应用程序并将源代码复制到容器中,Git使用Jenkins提取该代码。所以在我的工作区中,我在dockerfile中执行以下操作:
WORKDIR /app
COPY src src
虽然Jenkins使用Git正确更新主机上的文件,但Docker不会将此应用于我的图像。
我建立的基本脚本:
#!/bin/bash
imageName=xx:my-image
containerName=my-container
docker build -t $imageName -f Dockerfile .
containerRunning=$(docker inspect --format="{{ .State.Running }}" $containerName 2> /dev/null)
if [ "$containerRunning" == "true" ]; then
docker stop $containerName
docker start $containerName
else
docker run -d -p 5000:5000 --name $containerName $imageName
fi
我为--rm
尝试了--no-cache
和docker run
参数之类的不同内容,并在构建新之前停止/删除容器。我不确定我在这里做错了什么。似乎docker正在更新图像,因为调用COPY src src
会导致图层ID并且没有缓存调用:
Step 6 : COPY src src
---> 382ef210d8fd
更新容器的推荐方法是什么?
我的典型场景是:应用程序在Docker容器中的服务器上运行。现在部分应用程序已更新,例如通过修改文件。现在容器应该运行新版本。 Docker似乎建议构建一个新映像而不是修改现有容器,所以我认为像我这样重建的一般方法是正确的,但实现中的一些细节必须得到改进。
答案 0 :(得分:93)
经过一些研究和测试,我发现我对Docker容器的生命周期有一些误解。当图像在此期间重建时,简单地重新启动容器并不会使Docker使用新图像。相反,Docker只在运行容器之前获取图像。所以运行容器后的状态是持久的。
因此,重建和重新启动还不够。我认为容器就像服务一样:停止服务,进行更改,重新启动它们并应用它们。这是我最大的错误。
由于容器是永久性的,因此您必须先使用docker rm <ContainerName>
删除它们。移除容器后,您无法通过docker start
启动容器。这必须使用docker run
来完成,-rf
本身使用最新的映像来创建新的容器实例。
有了这些知识,可以理解为什么在容器中存储数据是qualified as bad practice而Docker建议使用data volumes/mounting host directorys:由于必须销毁容器以更新应用程序,因此存储的数据将在也迷失了。这会导致关闭服务,备份数据等的额外工作。
因此,将这些数据完全从容器中排除是一个明智的解决方案:我们不必担心我们的数据,当它安全地存储在主机上并且容器只保存应用程序本身时。
docker run
可能无法真正帮助您 -rf
命令有一个名为-rf
的清理开关。它将停止永久保留docker容器的行为。使用-d
,Docker将在退出后销毁容器。但是这个开关有两个问题:
-rf
开关虽然docker rm --force <ContainerName>
开关是在开发过程中为快速测试节省工作的好选择,但它在生产中不太适合。特别是因为缺少在后台运行容器的选项,这通常是必需的。
我们可以通过简单地删除容器来绕过这些限制:
--force
在运行容器上使用SIGKILL的-f
(或docker stop <ContainerName>
docker rm <ContainerName>
)开关。相反,您也可以在之前停止容器:
docker stop
两者都是平等的。 --force
也在使用SIGTERM。但是使用docker stop
开关会缩短您的脚本,尤其是在使用CI服务器时:containerRunning
如果容器未运行则会引发错误。这会导致Jenkins和许多其他CI服务器错误地将构建视为失败。要解决此问题,您必须首先检查容器是否正如我在问题中所做的那样运行(请参阅#!/bin/bash
imageName=xx:my-image
containerName=my-container
docker build -t $imageName -f Dockerfile .
echo Delete old container...
docker rm -f $containerName
echo Run new container...
docker run -d -p 5000:5000 --name $containerName $imageName
变量)。
根据这些新知识,我通过以下方式修复了我的脚本:
public $ftp_enable = '1';
这非常有效:)
答案 1 :(得分:9)
每当对dockerfile或compose或需求进行更改时,请使用import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
TestPane testPane = new TestPane();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(testPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
testPane.start();
}
});
}
});
}
public class Drawable {
private int x, y;
private Color color;
public Drawable(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColor() {
return color;
}
public void update() {
x--;
}
protected void reset(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public void paint(Graphics2D g2d) {
Graphics2D copy = (Graphics2D) g2d.create();
copy.translate(getX(), getY());
copy.setColor(getColor());
copy.fillOval(0, 0, 20, 20);
copy.setColor(Color.BLACK);
copy.drawOval(0, 0, 20, 20);
copy.dispose();
}
}
public class TestPane extends JPanel {
private List<Drawable> drawables;
private List<Drawable> decaying;
private List<Drawable> reusePool;
private Color[] colors = new Color[]{Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GREEN, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.YELLOW};
private Random rnd = new Random();
private Timer timer;
public TestPane() {
drawables = new ArrayList<>(2);
reusePool = new ArrayList<>(2);
decaying = new ArrayList<>(2);
timer = new Timer(40, new ActionListener() {
private List<Drawable> spawned = new ArrayList<>(5);
@Override
public void actionPerformed(ActionEvent e) {
spawned.clear();
Iterator<Drawable> it = drawables.iterator();
int swapnPoint = getWidth() / 2;
while (it.hasNext()) {
Drawable drawable = it.next();
drawable.update();
if (drawable.getX() > 0 && drawable.getX() < swapnPoint) {
if (!decaying.contains(drawable)) {
decaying.add(drawable);
Drawable newDrawable = null;
if (reusePool.isEmpty()) {
System.out.println("New");
newDrawable = new Drawable(
getWidth() - 20,
randomVerticalPosition(),
randomColor());
} else {
System.out.println("Reuse");
newDrawable = reusePool.remove(0);
newDrawable.reset(getWidth() - 20,
randomVerticalPosition(),
randomColor());
}
spawned.add(newDrawable);
}
} else if (drawable.getX() <= -20) {
System.out.println("Pop");
it.remove();
decaying.remove(drawable);
reusePool.add(drawable);
}
}
drawables.addAll(spawned);
repaint();
}
});
}
public void start() {
drawables.add(new Drawable(getWidth(), 128, randomColor()));
drawables.add(new Drawable(getWidth(), 384, randomColor()));
timer.start();
}
protected int randomVerticalPosition() {
return rnd.nextInt(getHeight() - 20);
}
protected Color randomColor() {
return colors[rnd.nextInt(colors.length - 1)];
}
@Override
public Dimension getPreferredSize() {
return new Dimension(288, 512);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Drawable drawable : drawables) {
Graphics2D g2d = (Graphics2D) g.create();
drawable.paint(g2d);
g2d.dispose();
}
}
}
}
重新运行它。这样就可以重建和刷新图像
答案 2 :(得分:0)
您可以通过运行build
来运行特定服务的docker-compose up --build <service name>
,其中服务名称必须与您在docker-compose文件中的调用方式相匹配。
示例
假设您的docker-compose文件包含许多服务(.net应用程序-数据库-让我们加密...等),并且您只想更新docker-compose文件中名为application
的.net应用程序。
然后,您只需运行docker-compose up --build application
其他参数
如果要向命令中添加其他参数(例如-d
以便在后台运行),则该参数必须在服务名称之前:
docker-compose up --build -d application