3 minute read

μ  ν‚¨μŠ€ auto - Workspace disable ν•˜λŠ”λ²•

Jenkins automatically cleans up old workspaces using WorkspaceCleanupThread to manage disk space. This happens periodically, even without the cleanWs() command in your pipeline, ensuring efficient disk space usage.

Jenkins workspace

image

μ  ν‚¨μŠ€(Jenkins) μ—μ„œλŠ” 각각의 job build process λ§ˆλ‹€ κ³ μœ ν•œ workspace 을 μƒμ„±ν•˜μ—¬ μ‚¬μš©ν•©λ‹ˆλ‹€.

workspace μ—λŠ” build μ‹œ ν•„μš”ν•œ νŒŒμΌλ“€μ΄ μ €μž₯되며,

μ—¬λŸ¬ 번의 싀행에도 독립적인 ν™˜κ²½μ—μ„œ build κ°€ κ°€λŠ₯ν•˜λ„λ‘ μ œκ³΅ν•΄μ€λ‹ˆλ‹€.

workspace 에 μ μž¬λ˜λŠ” 파일의 크기가 큰 경우,

jenkins server 의 disk κ°€ 가득 μ°° 수 μžˆλŠ” λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.

이λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄,

νŒŒμ΄ν”„λΌμΈμ— cleanWs() λͺ…λ Ήμ–΄λ₯Ό μΆ”κ°€ν•˜μ—¬ 각 build process λ§ˆλ‹€ workspace λ₯Ό μ§€μ›Œμ£ΌλŠ” μž‘μ—…μ„ μ„ ν–‰/ν›„ν–‰ν•˜λ„λ‘ μ„€μ •ν•  수 있죠.

workspace λ₯Ό μœ μ§€ν•˜κ³  μ‹Άλ‹€λ©΄ cleanWs() λ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠμœΌλ©΄ 될 κ²ƒλ§Œ κ°™μ§€λ§Œ,

μ‹€μ œλ‘œλŠ” 일정 μ£ΌκΈ°κ°€ μ§€λ‚˜λ©΄ 였래된 workspace λŠ” 슀슀둜 μ œκ±°λ©λ‹ˆλ‹€.

운영 ν™˜κ²½μ—μ„œ λ™μž‘ν•˜κ³  있던 jenkins job 쀑 μΌλΆ€λŠ” νŒŒμ΄ν”„λΌμΈμ— cleanWs() λ₯Ό μ‚¬μš©ν•˜κ³  μžˆμ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

κ·ΈλŸΌμ—λ„ console log λ₯Ό 보면 clean workspace λ₯Ό μ‹œλ„ν•œ 것을 확인할 수 μžˆμ—ˆμ£ .

μ™œ μ΄λ ‡κ²Œ λ™μž‘ν•˜λŠ” 지, μ‚΄νŽ΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€.

WorkspaceCleanupThread

μ„œμΉ˜ν•΄λ³΄λ‹ˆ μ  ν‚¨μŠ€ μ‹œμŠ€ν…œ λ‚΄μ—μ„œ 주기적으둜 workspace λ₯Ό cleanup ν•˜μ—¬, μ  ν‚¨μŠ€ μ„œλ²„μ˜ disk 곡간을 κ΄€λ¦¬ν•œλ‹€κ³  ν•©λ‹ˆλ‹€.

κ΄€λ ¨ μ„ΈλΆ€ λ‘œμ§μ€ WorkspaceCleanupThread.java μ—μ„œ 확인할 수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

주의깊게 확인해야 ν•˜λŠ” λΆ€λΆ„μ—λŠ” ⭐️이λͺ¨μ§€λ₯Ό λ‹¬μ•„λ‘μ—ˆμŠ΅λ‹ˆλ‹€.

/**
 * Clean up old left-over workspaces from agents.
 *
 * @author Kohsuke Kawaguchi
 */
@Extension @Symbol("workspaceCleanup")
public class WorkspaceCleanupThread extends AsyncPeriodicWork {
    // ... μƒλž΅ ...
    @Override protected void execute(TaskListener listener) throws InterruptedException, IOException {
        if (disabled) { <------ ⭐️
            LOGGER.fine("Disabled. Skipping execution");
            return;
        }
        // ... μƒλž΅ ...
        for (TopLevelItem item : j.allItems(TopLevelItem.class)) {
            if (item instanceof ModifiableTopLevelItemGroup) { // no such thing as TopLevelItemGroup, and ItemGroup offers no access to its type parameter
                continue; // children will typically have their own workspaces as subdirectories; probably no real workspace of its own
            }
            listener.getLogger().println("Checking " + item.getFullDisplayName());
            for (Node node : nodes) {
                FilePath ws = node.getWorkspaceFor(item);
                if (ws == null) {
                    continue; // offline, fine
                }
                boolean check;
                try {
                    check = shouldBeDeleted(item, ws, node); <------ ⭐️
                } catch (IOException | InterruptedException x) {
                    Functions.printStackTrace(x, listener.error("Failed to check " + node.getDisplayName()));
                    continue;
                }
                if (check) { <------ ⭐️
                    listener.getLogger().println("Deleting " + ws + " on " + node.getDisplayName());
                    try {
                        ws.deleteRecursive(); <------ ⭐️
                        WorkspaceList.tempDir(ws).deleteRecursive(); <------ ⭐️
                    } catch (IOException | InterruptedException x) {
                        Functions.printStackTrace(x, listener.error("Failed to delete " + ws + " on " + node.getDisplayName()));
                    }
                }
            }
        }
    }

    private boolean shouldBeDeleted(@Nonnull TopLevelItem item, FilePath dir, @Nonnull Node n) throws IOException, InterruptedException {
        // ... μƒλž΅ ...
        if(dir.lastModified() + retainForDays * DAY > now) { <------ ⭐️
            LOGGER.log(Level.FINE, "Directory {0} is only {1} old, so not deleting", new Object[] {dir, Util.getTimeSpanString(now-dir.lastModified())});
            return false;
        }
        // ... μƒλž΅ ...
        return true;
    }
    
    /**
     * Can be used to disable workspace clean up. <------ ⭐️
     */
    public static boolean disabled = SystemProperties.getBoolean(WorkspaceCleanupThread.class.getName()+".disabled");

    /**
     * How often the clean up should run. This is final as Jenkins will not reflect changes anyway. <------ ⭐️
     */
    public static final int recurrencePeriodHours = SystemProperties.getInteger(WorkspaceCleanupThread.class.getName()+".recurrencePeriodHours", 24);

    /**
     * Number of days workspaces should be retained. <------ ⭐️
     */
    public static int retainForDays = SystemProperties.getInteger(WorkspaceCleanupThread.class.getName()+".retainForDays", 30);
}

μœ„ μ½”λ“œλ₯Ό 톡해 μ•Œ 수 μžˆλŠ” 점을 μ •λ¦¬ν•΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€.

- recurrencePeriodHours μ£ΌκΈ°λ§ˆλ‹€ workspace clean up 을 μˆ˜ν–‰ (κΈ°λ³Έκ°’: 24 μ‹œκ°„)
- μ‚­μ œν•΄μ•Ό ν•  workspace λ₯Ό νŒλ‹¨ν•˜λŠ” 기쀀은, λ§ˆμ§€λ§‰ μˆ˜μ • μ‹œκ°„μ΄ retainForDays 보닀 μ˜€λž˜λ˜μ—ˆλŠ”μ§€λ₯Ό 체크 (κΈ°λ³Έκ°’: 30 일)

μ  ν‚¨μŠ€ job νŒŒμ΄ν”„λΌμΈμ—μ„œ cleanWs() λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šλ”λΌλ„, μ  ν‚¨μŠ€ μ„œλ²„μ—μ„œ workspace λ₯Ό clean up ν•˜λ €κ³  ν•œ μ΄μœ λŠ” 이제 λΆ„λͺ…ν•΄μ‘Œμ£ .

λ§Œμ•½, WorkspaceCleanupThread 에 μ˜ν•œ workspace clean up 이 μΌμ–΄λ‚˜μ§€ μ•Šλ„λ‘ λ°©μ§€ν•˜λ €λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Ό ν• κΉŒμš”?

WorkspaceCleanupThread.java μ½”λ“œλ₯Ό λ‹€μ‹œ ν™•μΈν•΄λ΄…μ‹œλ‹€.


@Override protected void execute(TaskListener listener) throws InterruptedException, IOException {
  if (disabled) { <------ ⭐️
    LOGGER.fine("Disabled. Skipping execution");
    return;
  }
  // ... μƒλž΅ ...
}

    /**
     * Can be used to disable workspace clean up. <------ ⭐️
     */
    public static boolean disabled = SystemProperties.getBoolean(WorkspaceCleanupThread.class.getName()+".disabled");

disabled 값에 λ”°λΌμ„œ 둜직이 μˆ˜ν–‰λ˜λŠ” 것을 μ•Œ 수 있고, ν•΄λ‹Ή 값은 ν™˜κ²½ λ³€μˆ˜λ‘œ μ „λ‹¬λ°›μœΌλ―€λ‘œ

Jenkins μ‹œμž‘ μ‹œ,

-Dhudson.model.WorkspaceCleanupThread.disable=true λ₯Ό μΆ”κ°€ν•˜μ—¬ workspace clean up 을 λΉ„ν™œμ„±ν™” ν•  수 μžˆμŠ΅λ‹ˆλ‹€.


잘λͺ»λœ 뢀뢄이 μžˆλ‹€λ©΄ comment λ‚¨κ²¨μ£Όμ„Έμš”!


References

Categories:

Updated:

Leave a comment